Android性能优化系列——内存优化

内存,是Android应用的生命线,一旦在内存上出现问题,轻者内存泄漏造成App卡顿,重者直接crash,因此一个应用保持健壮,要做好内存的使用和优化。网上有很多讲JAVA内存虚拟机的好文章,我就不赘述了。今天主要总结下内存优化。

作为一个开发者,需要在平时的代码中就要多注意,如有不合理的地方,则需要进行优化。

一、内存泄漏(memory leak):

内存泄漏就是在当前应用周期内不再使用的对象被GC Roots引用,导致不能回收,使实际可使用内存变小,通俗点讲,就是无法回收无用对象。

二、内存溢出(out of memory,也叫OOM):

系统在申请内存空间时,没有总够的内存空间供其使用。简单来说就是系统不能再分配你所需要的内存空间,比如你申请需要100M的内存空间,但是系统仅剩90M了,这时候就会内存溢出。(溢出会导致应用Crash崩溃)

内存泄漏的本质原因:

本该被回收的对象没有被回,继续停留着内存空间中,导致内存被占用。其实是持有引用者的生命周期 > 被持有引用者的生命周期。过多内存泄漏会把内存空间占用完,最终会导致内存溢出。

三、内存泄漏的常见情况

1.非静态内部类创建静态实例

非静态内部类创建静态实例会导致内存泄漏,通常项目中,通常在Activity启动的时候创建单例数据,避免重复创建相同的数据,会在Activity内部创建一个非静态内部类的静态实例。

错误的例子:非静态内部类默认持有外部引用

public class NotStaticActivityextends AppCompatActivity {//非静态内部类实例引用,设置为静态private static InnerClass sInnerClass;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);//保证非静态内部类实例只有一个if (sInnerClass == null) {sInnerClass = new InnerClass();}}//非静态内部类private class InnerClass {//……}
}

非静态外部类(InnerClass)的生命周期 = 应用的生命周期,而且持有外部类Activity的引用,在Activity在销毁的时候无法被GC回收,从而导致内存泄漏。

优化后的代码1:将非静态内部类设置为静态内部类(静态内部类默认不持有外部类的引用)

  //静态内部类private static class InnerClass2 {//……}

优化后的代码2:将外部类抽取出来封装成一个单例

public class InnerClass  extends AppCompatActivity {private static final String TAG = InnerClass3.class.getSimpleName();private static InnerClass sInnerClass;//单例public InnerClass getInstance() {if (sInnerClass == null) {sInnerClass = new InnerClass();}return sInnerClass;}
}
2.注册对象未注销或资源对象未关闭

注册了像BraodcastReceiver,EventBus这种,没有在页面销毁时注销的话,会引发泄露问题,所以应该在Activity销毁时及时注销。

3.多线程造成内存泄漏

我们知道线程类属性非静态(匿名)内部类,多线程的使用主要是AsyncTask、实现Runnable接口,继承Thread类,在使用线程类时需要注意内存泄漏。

1).AsyncTask

我们常常使用AsyncTask来执行一些异步的耗时操作。

我们需要在界面销毁的时候调用AsyncTask.cancel(true)方法。

@Overrideprotected void onDestroy() {//强制退出AsyncTaskmAsyncTask.cancel(true);super.onDestroy();}

2).Thread和Handler的使用

Thread:线程类Thread属于非静态内部类,它的生命周期比ThreadActivity的生命周期长,运行时默认持有外部类的引用,如果ThreadActivity需要销毁时,线程类Thread持有ThreadActivity的引用,导致ThreadActivity无法回收利用,造成内存泄漏。

我们经常这样使用:

//方式一:新建内部类new MyThread().start();//方式二:匿名Thread内部类new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}}}).start();}//自定义Threadprivate class MyThread extends Thread {@Overridepublic void run() {try {Thread.sleep(1000);} catch (Exception e) {e.printStackTrace();}}}

优化方法1;把 private class MyThread extends Thread改成静态内部类  private static class MyThread extends Thread;

优化方法2:在界面的ondestroy方法中,把线程结束掉.

Handler:也是一个内部类,我们在使用的时候也会提示他如果是非静态的,就会造成内存泄漏。

解决方法1:

  如果 Handler 不需要外部 Activity 的数据,直接使用使用静态内部类或外部类即可,避免使用成员内部类。如果需要,还可以使用外部类+弱引用的方法。

private static class MyHandler extends Handler {private WeakReference<MainActivity> ref;public MyHandler(Activity activity) {this.ref = new WeakReference<>(activity);}@Overridepublic void handleMessage(@NonNull Message msg) {// TODO:ref.get()...super.handleMessage(msg);}
}

tips:使用成员内部类 + 弱引用的方法是不行的,内部类默认持有外部类引用的。

解决方法2:当外部类结束生命周期时,清空Handler内消息队列;

   @Overrideprotected void onDestroy() {//当外部类结束生命周期时,清空Handler内消息队列;mHandler.removeCallbacksAndMessages(null);super.onDestroy();}
4.static关键字修饰的成员变量

我们知道被static修饰的成员变量的生命周期等于app应用程序的生命周期。

所以,是否有些不需要的是否可以去掉,静态的改成非静态的。

如果静态的对象引用了activity,是否可以替换成App的上下文就足够了。

5.引用的对象是否回收,置空

(1)动画相关资源使用后,记得及时回收;

(2)IO流相关类:在使用IO流,File文件类或者Sqlite、Cursor等资源时要及时关闭,这些资源在读写操作时一般都行了缓冲,如果不及时关闭,这些缓冲对象就会一直被占用得不到释放,以致内存泄漏,所以在在它们不需要使用时,及时关闭,缓冲释放资源,避免内存泄漏。

  1. stream.close();

  2. cursor.close();

  3. bitmap.recycle();bitmap = null;

  4. arrayList.clear();arrayList = null;

6、内存抖动

当大量的对象创建又回收时,就会内存抖动,例如常见的在onDraw方法中创建对象,应把对象放在类中或者初始化方法中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/606744.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL必知必会笔记(9~12章)

第九章 汇总数据 1、聚集函数用来进行记录数据的加工&#xff0c;然后再进行返回。 2、SQL的聚集函数&#xff1a; 函数 说明 AVG() 返回某列的平均值 COUNT() 返回某列的行数 MAX() 返回某列的最大值 MIN() 返回某列的最小值 SUM() 返回某列值之和 3、AVG()函数 A…

想要成为机器学习领域的高手吗?这里有五本必读免费书,订阅周报发链接 (下)

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Azure AI 内容安全Content Safety Studio实战

Azure AI Content Safety 检测应用程序和服务中用户生成和 AI 生成的有害内容。 Azure AI 内容安全包括文本和图像 API&#xff0c;可用于检测有害材料。 交互式 Content Safety Studio&#xff0c;可用于查看、浏览和试用用于检测不同形式的有害内容的示例代码。 关注TechLead…

项目框架构建之6:编写通用主机基础类

本文是“项目框架构建”系列之6&#xff0c;本文介绍如何编写通用主机基础类。 1.为了构建通用主机&#xff0c;我们先创建主机接口IAppHost接口 接口需要有配置项&#xff0c;我们定义为HostConfiguration&#xff0c;比如我们希望用户可以设定他的工作目录&#xff0c;就可…

深度学习|4.7 参数和超参数

4.7 参数和超参数 超参数是指需要用户提前设置好的参数&#xff0c;这些超参数最终会影响到参数的数值&#xff08;相当于参数是动态调整得到的&#xff09; 学习率的选取 最优学习率应该能使得代价函数趋于一个较低的常数。

接口工具Apifox

最近发现一款接口测试工具--apifox&#xff0c;我我们很难将它描述为一款接口管理工具 或 接口自测试工具。 官方给了一个简单的公式&#xff0c;更能说明apifox可以做什么。 Apifox Postman Swagger Mock JMeter Apifox的特点&#xff1a; 接口文档定义&#xff1a; Apif…

CSS 发光输入框动画

<template><view class="content"><input placeholder="请输入..." class="input" /> </view> </template><script></script><style>/* 设置整个页面的背景颜色为 #212121 */body{background-c…

react native中使用tailwind并配置自动补全

使用的第三方库是tailwind-react-native-classnames&#xff0c;同类的也有tailwind-rn&#xff0c;但是我更喜欢前者官方demo&#xff1a; import { View, Text } from react-native; import tw from twrnc;const MyComponent () > (<View style{twp-4 android:pt-2 b…

【办公技巧】excel中设置选项按钮的方法

大家是否会遇到需要勾中选项的情况&#xff0c;我们可以在电子表格中制作出可以勾选、选中的选项按钮&#xff0c;今天我们一起学习一下设置方法。 首先&#xff0c;我们需要先在excel工具栏中添加一个功能模块&#xff1a;开发工具 依次点击excel中的文件 – 选项 – 自定义…

第二百五十三回

文章目录 概念介绍使用方法示例代码 概念介绍 进度条是常用的组件之一&#xff0c;它主要用来显示某种动作的完成进度。Flutter提供了多种进度条组件&#xff0c;常用的是水平进度条&#xff1a;LinearProgressIndicator&#xff1b;圆形进度条 :CircularProgressIndicator和R…

2023年,To B资本航船走向哪了?

国内To B领域在去掉泡沫、结束资本狂欢之后&#xff0c;投资决策愈加理性。但与此同时&#xff0c;下滑的步伐正在放慢&#xff0c;交易数量和金额的降低逐渐放缓&#xff0c;市场逐渐走向稳定。 作者|斗斗 编辑|皮爷 出品|产业家 2023年&#xff0c;在一众业内人士的眼中&…

文件系统与日志分析

一&#xff0c;文件系统 &#xff08;一&#xff09;inode 和block概述 1&#xff0c;文件数据包括元信息与实际数据 2&#xff0c;文件存储在硬盘上&#xff0c;硬盘最小存储单位是“扇区”&#xff0c;每个扇区存储512字节 3&#xff0c;block (块) 连续的八个扇区组成一…

从零开始了解Figma:全面介绍这款设计工具,让你熟练运用!

什么是Figma&#xff1f; 它是一个类似于Sketch或XD的UI设计工具&#xff0c;但Figma和后两者的本质区别在于它是基于web的&#xff0c;也就是说&#xff0c;只要有浏览器和网络&#xff0c;它就可以打开和使用。 Figma为什么强大&#xff1f; Windows上最好的UI设计工具 由…

Redisson 源码解析 - 分布式锁实现过程

一、Redisson 分布式锁源码解析 Redisson是架设在Redis基础上的一个Java驻内存数据网格。在基于NIO的Netty框架上&#xff0c;充分的利用了Redis键值数据库提供的一系列优势&#xff0c;在Java实用工具包中常用接口的基础上&#xff0c;为使用者提供了一系列具有分布式特性的常…

一文搞定JMM核心原理

公众号《鲁大猿》&#xff0c;寻精品资料&#xff0c;帮你构建Java全栈知识体系 www.jiagoujishu.cn &#xff08;架构技术.cn&#xff09; JMM引入 从堆栈说起 JVM内部使用的Java内存模型在线程栈和堆之间划分内存。 此图从逻辑角度说明了Java内存模型&#xff1a; # 堆栈里…

SpringBoot + Mybatis 实现多数据源原来如此简单

1、为什么需要整合多数据源 在开发的过程中&#xff0c;我们可能会遇到一个工程使用多个数据源的情况&#xff0c;总体而言分为以下几个原因 a、数据隔离&#xff1a;将不同的数据存储在不同的数据库中&#xff0c;如多租户场景 b、性能优化&#xff1a;将数据分散到多个数据库…

【野火i.MX6ULL开发板】利用microUSB线烧入Debian镜像

0、前言 烧入Debian镜像有两种方式&#xff1a;SD卡、USB SD卡&#xff1a;需要SD卡&#xff08;不是所有型号都可以&#xff0c;建议去了解了解&#xff09;、SD卡读卡器 USB&#xff1a;需要microUSB线 由于SD卡的网上资料很多了&#xff0c;又因为所需硬件&#xff08;SD卡…

Spring应用的部署与管理

一、前言 部署是将开发好的应用发布到服务器上&#xff0c;使其能够被用户访问的关键步骤。Spring框架提供了灵活的部署选项&#xff0c;本文将介绍Spring应用的常见部署方式和一些建议&#xff0c;帮助开发者顺利将应用投放到生产环境。 二、传统部署方式&#xff1a;WAR包 传…

09Bean的生命周期及循环依赖

Spring其实就是一个管理Bean对象的工厂。它负责对象的创建&#xff0c;对象的销毁等。 所谓的生命周期就是&#xff1a;对象从创建开始到最终销毁的整个过程。 Bean的生命周期之5步 ● 第一步&#xff1a;实例化Bean(无参构造方法执行) ● 第二步&#xff1a;Bean属性赋值(注…

基于YOLOv7算法的高精度实时19类动物目标检测识别系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法的高精度实时19类动物目标检测系统可用于日常生活中检测与定位19类动物目标&#xff08;水牛、 斑马、 大象、 水豚、 海龟、 猫、 奶牛、 鹿、 狗、 火烈鸟、 长颈鹿、 捷豹、 袋鼠、 狮子、 鹦鹉、 企鹅、 犀牛、 羊和老虎&#xff09;&#x…