Android性能优化,有关内存抖动与解决方案

news2024/9/28 3:31:31

一、内存抖动

1.内存抖动的危害

由于垃圾回收机制老年代里面的标记清理算法,大有大量对象创建并快速销毁后,会在内存里面留下大量的内存碎片,这时如果有大对象需要申请内存时,就会产生OOM。

2.如何查看程序是否有内存抖动现象

可以利用Android studio 的profiler工具

当内存出现大量小幅度升降时,即可判断为内存抖动

3.比较常见造成内存抖动的场景

造成内存抖动的原因是在短时间内创建了大量的对象,所以我们特别应该避免在频繁调用的方法里面创建对象。

(1)字符串拼接

String str = "一"+ "二"+"三"+"四";

在JVM将java代码翻译成字节码的时候,String对象的每次拼接都会创建StringBuilder对象。 优化方案:我们可以自己StringBuilder对象

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("一");
stringBuilder.append("二");
stringBuilder.append("三");
stringBuilder.append("四");

(2)在循环里面创建对象

如果循环次数过多,直接在循环体里面创建对象可能需要慎重考虑,能在循环外面创建对象的尽量在外面创建。

(3)在onDraw 里面创建对象

onDraw也是调用比较频繁的函数,所以创建对象也需要慎重考虑,比如Paint、Path的创建可以在View初始化的时候就创建,如果要在onDraw里面对其改变,直接重置即可。

二、内存泄漏

内存泄漏是指程序中已分配的内存,由于某种原因,没有被释放或者是无法被释放,造成内存浪费的现象。主要是短生命周期对象强引用了长生命周期,导致短生命周期对象该被回收的时候无法被回收。

1.内存泄漏的危害

大量的内存泄漏会直接导致程序浪费大量的内存,从而导致系统OOM

2.如何查看程序中是否有内存泄漏

项目中主要的内存泄漏是Activity的内存泄漏,如果我们怀疑SecondActivity 存在内存泄漏,可以用 Android studio 的profiler工具和MAT工具查看。

我们在App里面频繁进出SecondActivity ,如果内存状态如下图所示持续增加,则说明可能存在内存泄漏,需要继续查找

这时需要点上门的下载按钮,将此时的内存状态dump下来。dump下来后,profiler会自动显示如下Heap Dump数据,我们以Arrange by package 排序,去对应包名下找我们检测的SecondActivity 对象是否存在,如下图所示,这里存在6个SecondActivity 对象以及6个SecondActivity 内部类对象。

看到这里我们只能知道内存中存在SecondActivity 对象,但并不代表就存在内存泄漏,因为内存泄漏是需要被其他对象强引用。所以我们需要借助另一个工具MAT。 我们先需要将当前看到的内存文件以hprof的格式导出来,直接在profiler窗口的右边对应的session 右键即可导出。由于Android studio 导出来的hprof文件并非标准hprof文件,所以需要先用借助Android sdk 安装目录下platform-tools目录下的hprof-conv.exe工具转换下。

hprof-conv -z D:\workspace\09.05\memory-20200905T142908.hprof  D:\workspace\09.05\1.hprof

备注:hprof-conv命令需要配置环境变量 用MAT 以open heap file 的方式打开转换后的1.hprof文件

如上图所示,点1处可以列出内存中所有对象,点2处可以输入想要查找的对象名称

查到对应的对象后,右键按右键选Merge Shortest Paths to GC Roots ——> exclude all phantom/weak/soft etc.references 去除掉虚引用、弱引用、和软引用。 这时如果还存在对象,就说明SecondActivity 确实存在内存泄漏 再点开过滤虚引用、弱引用、和软引用后还存在的对象,如下图所示

可以看出是系统InputMethodManager引起的内存泄漏。规避方案网上很多,这里就不详述了。

3.内存泄漏的常见场景

(1)将Activity 的context对象传入单例类

由于单例类的的对象经常是static的,而static对象可作为垃圾回收机制的GCRoots对象,也就是单例类的对象的生命周期远远高于Activity的生命周期,所以会造成内存泄漏 优化方案:先看看是否是必须传context,一般Activity 的context只在UI层传递即可。如果必须要传context对象,可以考虑传Application的context。

(2)匿名内部类的使用

举例

public class SecondActivity extends Activity {public static final String TAG = "SecondActivity";private Handler handler ;private void handleMsg(){handler.postDelayed(new Runnable() {@Overridepublic void run() {}},2000);}
...
}

由于匿名内部类会含有外部类的引用对象,上面代码Runnable对象中就会引用SecondActivity 对象,所以会造成内存泄漏。 优化方案1: 在SecondActivity 的onDestroy方法中调用handler.removeCallbacksAndMessages(null)可从Handler 队列中移除所有的Runnable对象,从而打断引用链。

@Override
protected void onDestroy() {super.onDestroy();handler.removeCallbacksAndMessages(null);
}

优化方案2: 将Runnable写成静态内部类,静态内部类不会引用外部类的对象。如果静态内部类中需要用到外部类的对象,可以用弱引用传进去。对应代码如下:

public class SecondActivity extends Activity {public static final String TAG = "SecondActivity";private Handler handler ;private MyRunnable myRunnable = new MyRunnable(this);static class MyRunnable implements Runnable{WeakReference<SecondActivity> reference ;public MyRunnable(SecondActivity activity){reference = new WeakReference<SecondActivity>(activity);}@Overridepublic void run() {SecondActivity secondActivity = reference.get();if(null != secondActivity ){//to do something}}}private void handleMsg(){handler.postDelayed(myRunnable,2000);}...
}

(3)集合的使用

入股集合中的某个元素对象 后期不用了,需要把这个元素remove掉。

(4)监听器的使用

设置的监听器,在监听页面销毁的时候,记得把监听器清除掉。

(5)未释放资源

比如文件流未关闭,这里一定要保证在finally中把每个流单独try catch全都关掉,以防在前面关流过程中就发生了异常,后面的留就无法关闭了。

(6)系统bug

如WebView 、InputMethodManager

内存抖动方案解决

1.集合类

集合类如果仅仅有添加元素的机制,而没有相应删除元素机制,这样就会造成内存被占用,如果这个类是全局性变量(比如类中有静态属性,全局性的map等即有静态引用或final一直指向它)。那么没有相应删除机制,很可能导致集合所占内存只增不减。 解决办法:在使用集合类时,增加删除元素机制,并适当调用减少集合所占内存。

2.单例模式

不正确使用单例模式,也会引起内存泄漏单例对象在初始化后将在JVM的整个生命周期存在(以静态变量方式),如果单例对象持有外部对象的引用,那么这个外部对象就会一直占用着内存,可能导致内存泄漏(取决于这外部对象是否一致有用)。 解决办法:单例对象中避免含有不是一直都有用的外部对象引用。

3.Android组件或特殊集合对象的使用

BraodcastReceiver ,ContentObserver,fileObserver,Cursor,Callback等在Activity onDestory或者某类生命周期结束之后一定要unregistere或者close掉,否则这个Activity类会被system强引用,不会被回收。不要直接对Activity进行直接引用作为成员变量,如果不得不这么做,调用private WeakPeferense mActivity 来做,相同的,对与Service等其他有自己生命周期的对象来说,直接引用都需要考虑是否会存在内存泄露的可能。

4.Handler

要知道,只要Handler 发送的Message尚未被处理,则该Message及发送它的Handler对象将被线程MessageQueue一直持有。由于Handler属于TLS(Thread Local Storage)变量,生命周期和Activity是不一致的。因此这种实现方式一般很难保证跟view或者Activity的生命周期保持一致,故很容易导致无法正确释放。如上所述,Handler使用要特别小心,否则很可能内存泄漏。 解决办法:在view 或者Activity生命周期结束前,确保Handler已没有未处理的消息(特别是延时消息)。

5.Thread 内存泄漏

线程也是造成内存泄露的一个重要源头,线程产生内存泄露的主要原因在于线程生命周期不可控,比如线程是Activity的内部类,则线程对象中保存了Activity的一个引用,当线程的run函数耗时较长没有结束时,线程对象是不会被销毁的,因此它所引用的老的Activity就出现了内存泄漏问题。解决办法:1.简化线程run函数执行的任务,使他在Activity生命周期结束前,任务运行完。2.为Thread增加撤销机制,当Activity生命周期结束时,将Thread的耗时任务撤销(笔者推荐这种)。

6.一些不良代码造成的内存压力

有些代码并不造成内存泄漏,但是他们是对没使用的内存没进行有效及时的释放,或是没有有效的利用已有的对象而是频繁的申请新内存。

(1) Bitmap 没调用recycle()

Bitmap 对象在不使用时,我们应该先调用recycle()释放内存,然后才置空,因为加载bitmap对象的内存空间,一部分是java的,一部分是c的(因为Bitmap分配的底层是通过jni调用的,Android的Bitmap底层是使用skia图形库实现,skia是用c实现的)。这个recycle()函数就是针对c部分的内存释放。

(2)构造Adapter时,没有使用缓存的convertView。 解决办法:使用静态holdview的方式构造Adapter。

这样到这里内存抖动和内存泄漏的发现,定位以及解决方法以说明完毕。

内存抖动一直是Android性能优化的重要环节,Android的性能优化除了内存抖动导致的卡顿外,还有布局优化、卡顿优化、启动优化等等。Android性能优化也是大厂面试的必备技术,面试也是被常常问及到的问题。

更多有关Android性能优化的技术进阶学习,可以参考《Android性能优化手册》这个文档。里面包含了在Android性能优化这块的技术点的解析。点击可以查看详细类目。

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

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

相关文章

小白网络安全学习手册—黑客

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高&#xff1b; 二、则是发展相对成熟…

安防视频监控平台EasyCVR出现“no space left on device磁盘空间不足”是什么原因?该如何解决?

视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多路视频流&#…

BM74 数字字符串转化成IP地址

数字字符串转化成IP地址_牛客题霸_牛客网现在有一个只包含数字的字符串&#xff0c;将该字符串转化成IP地址的形式&#xff0c;返回所有可能的情况。。题目来自【牛客题霸】https://www.nowcoder.com/practice/ce73540d47374dbe85b3125f57727e1e?tpId295&tags&title&a…

Vue思考题_01v-for与v-if的优先级谁更高

目录 vue2vue3 官方文档上说不推荐将v-for与v-if在同一个标签上使用&#xff0c;因为两者优先级并不明显。 那么到底是那个指令的优先级比较高呢&#xff1f; 在vue2与vue3中答案是相反的。 vue2 在vue2中将2个指令放在同一个标签上 <template><ul><li v-fo…

2023-10-10-C++指针和引用【程序员生涯的第一座里程碑】

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

中职院校网络综合布线技术理实一体化实训室建设方案

中职院校的网络综合布线技术课程存在一些问题,主要表现在: 教师过于注重理论知识的讲授,实践教学被忽视。学校硬件设施不足,无法开展案例中的实际操作,影响学生实践能力的培养。学生进入工作后,实际操作能力较差,难以胜任工作岗位。 为了提高学生的网络综合布线技能和操作能力…

碰撞检测算法——分离轴算法实现(一)

在实现分离轴算法前&#xff0c;需要做一些准备工作&#xff0c;在Unity中实现自定义多边形的显示&#xff0c;以及获取多边形的顶点和边的数据。 1.实现自定义多边形显示 Unity中MeshFilter是负责处理Mesh&#xff08;网格&#xff09;的信息的引用&#xff0c;MeshRender是渲…

管程的定义以及基本特征

1.引入管程 为了解决信号量机制存在的问题&#xff1a;编写程序困难、易出错。 1973年&#xff0c;Brinch Hansen首次在程序设计语言(Pascal)中引入了“管程”成分&#xff1a;一种高级同步机制。 2.管程的定义和基本特征 1.管程是一种特殊的软件模块&#xff0c;有这些部分…

Leetcode——数组的遍历系列练习

485. 最大连续 1 的个数 class Solution { public:int findMaxConsecutiveOnes(vector<int>& nums) {// 记录最大连续1个数int max 0;// 记录数组中存在1个数int sum 0;// 遍历连续1个数int count 0;for (int i 0; i < nums.size() - 1; i) {if (nums[i] 1)s…

linux | linux扩大磁盘空间 | centos7.9 | 虚拟机

注意&#xff1a;可以完全参考下面这边博客&#xff08;我只是搬运工&#xff09; centos扩大磁盘空间 简单讲讲&#xff0c;为什么有点失落落的&#xff1f; 明明就是一个 很程序化的东西 可是网上一大推 天花乱坠 而且很多人都是半吊子水&#xff0c;甚至半吊子都没有 通过关…

jdbc(DriverManager+Connection+Statement+ResultSet)+SQL注入+开启预编译+数据连接池

1 JDBC概念 JDBC 就是使用Java连接并操作数据库的一套API 全称&#xff1a;( Java DataBase Connectivity ) Java 数据库连接 2 JDBC优势 可随时替换底层数据库&#xff0c;访问数据库的Java代码基本不变 以后编写操作数据库的代码只需要面向JDBC&#xff08;接口&#xf…

裸辞18K外包,面试阿里、字节全都一面挂,哭死.....

测试员可以先在外包积累经验&#xff0c;以后去大厂就很容易&#xff0c;基本不会被卡&#xff0c;事实果真如此吗&#xff1f;但是在我身上却是给了我很大一巴掌... 所谓今年今天履历只是不卡简历而已&#xff0c;如果面试答得稀烂&#xff0c;人家根本不会要你。况且要不是大…

[软件工具]ARW文件批量转图片jpg工具使用教程

当你有一批后缀为.ARW格式图像文件怎么转jpg呢&#xff0c;我们可以使用这个工具进行转换首先我们打开软件 然后我们直接导入文件夹&#xff0c;点击开始转换等待转换完成即可。详细视频教程参看&#xff1a; ARW文件批量转图片jpg png bmp工具使用教程_哔哩哔哩_bilibili这个…

自动化测试基础篇:Selenium 框架设计(POM)

【导语】Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。本文介绍selenium的框架设计。 自动化测试框架 1.什么是自动化测试框架 简单来说&#xff0c;自动化测试框架就是由一些标准&#xff0c;协议&…

Vue-2.1scoped样式冲突

默认情况&#xff1a;写在组件中的样式会全局生效->因此很容易造成多个组件之间的样式冲突问题 1.全局样式&#xff1a;默认组件中的样式会作用到全局 2.局部样式&#xff1a;可以给组件加上scoped属性&#xff0c;可以让样式只作用于当前组件 <style scoped> <…

长沙建筑模板生产厂家有哪些?

在湖南长沙地区&#xff0c;建筑施工企业寻找一家可信赖的建筑模板供应商是非常重要的。在长沙地区&#xff0c;有多家建筑模板生产厂家&#xff0c;其中值得一提的是能强优品木业&#xff0c;他们是长沙地区建筑模板生产的领先供应商之一。 能强优品木业位于广西贵港市&#x…

Leetcode: 63. 不同路径 II(动态规划)

1. 题目解析 LeetCode链接 根据题目可以得出&#xff0c;当处于 [i][j] 位置时只能从 [i][j - 1], 和 [i - 1][j] 到达&#xff0c;所以我们只需要将到达上述两点的路径相加就可以得到到达该点的路径和 2. 解题思路 通过分析题目我们可以使用动态规划来解决这道题 首先我们…

【计算机网络笔记】什么是计算机网络?

前言计算机网络的定义交换网络什么是Internet从组成细节角度看从服务角度看 最后感谢 &#x1f496; 本篇文章总字数&#xff1a;1342字 预计阅读时间&#xff1a;5~10min 建议收藏之后慢慢阅读 前言 计算机网络通信技术计算机技术。 计算机网络是通信技术与计算机技术紧密结…

求后缀表达式的值

后缀表达式的值 【题目描述】 从键盘读入一个后缀表达式&#xff08;字符串&#xff09;&#xff0c;只含有0-9组成的运算数及加&#xff08;&#xff09;、减&#xff08;—&#xff09;、乘&#xff08;*&#xff09;、除&#xff08;/&#xff09;四种运算符。每个运算数之间…