草庐IT

Android内存抖动(主要原因分析+6个优化小技巧)

谁动了我的代码 2023-03-28 原文

内存抖动概念

在程序里,每创建一个对象,就会有一块内存分配给它;每分配一块内存,程序的可用内存也就少一块;当程序被占用的内存达到一定临界程度,GC 也就是垃圾回收器(Garbage Collector)就会出动,来释放掉一部分不再被使用的内存。

Android 里的 View.onDraw() 方法在每次需要重绘的时候都会被调用,这就意味着,如果你在 onDraw() 里写了创建对象的代码,在界面频繁刷新的时候,你就也会频繁创建出一大批只被使用一次的对象,这就会导致内存占用的迅速攀升;然后很快,可能就会触发 GC 的回收动作,也就是这些被你创建出来的对象被 GC 回收掉。

[垃圾内存]太多了就被清理掉,这是 Java 的工作机制,这不是问题。问题在于,频繁创建这些对象会造成内存不断地攀升,在刚回收了之后又迅速涨起来,那么紧接着就是又一次的回收,对吧?这么往复下来,最终导致一种循环,一种在短时间内反复地发生内存增长和回收的循环。

这种循环往复的状态就像是水波纹的颤动一样,它的专业称呼叫做 Memory Churn,Android 的官方文档里把它翻译做了内存抖动。

简单来说就是: 在程序需要对象的时候,在堆当中分配出来一块空间,使用完毕以后, GC 帮我们清理掉这片内存空间,如果频繁的一直持续上述操作,就会引起内存抖动。

内存抖动原因分析

Android Studio提供了一个 profile的工具,可以帮助我们分析内存情况,在studio的上不有一个表盘的图标


点击红框图标,然后就会运行当前项目,选中连接的手机,然后在studio的底部就会出现一个Android Profile的工具项(如下图)。


我们会看到有CPU,MEMORY,NETWORK三个选项,我们要监控的是内存,所以点击MEMORY,会进入下图


在这张图中我们可以看到我们当前应用所占的内存total,我们这里重点说一下左上角的三个按钮分别是:

  • GC手动垃圾回收
  • 收集当前页面的内存情况并生成hprof文件
  • 记录当前操作的内存情况

首先我们调用GC是当前内存处于稳定状态,然后点击红色按钮开始记录内存状况,然后我们开始在手机上进行操作(一般这个时候会发现平稳的曲线开始波动),然后我们点击停止按钮,回出现下图的情况。![Android内存抖动分析与注意事项]

框框内是我们当前记录的操作区间,当我们点击停止按钮的时候,
在Class Name这个框内,会生成当前记录区间(操作过程)的堆信息。

我们发现我们的曲线有一个向上的陡坡,说明我们的操作造成了大量的内存分配,通过下面堆信息我们来找一下是什么造成了大量的内存分配。


我们发现堆信息是从大到小排列的,而第一条是系统的imageView,明显这里有问题,点击进去发现有大量的imageView对象,点击其中的一个,右下角的框框会显示该对象的具体位置信息。至此我们找到了造成内存抖动的罪魁祸首,

当然,这里的内存抖动是我人为加上去的,比较明显,但是原理是一样的。

内存抖动方案解决

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内存抖动(主要原因分析+6个优化小技巧)的更多相关文章

  1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  2. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  3. ruby-on-rails - Ruby 中的内存模型 - 2

    ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

  4. 动漫制作技巧如何制作动漫视频 - 2

    动漫制作技巧是很多新人想了解的问题,今天小编就来解答与大家分享一下动漫制作流程,为了帮助有兴趣的同学理解,大多数人会选择动漫培训机构,那么今天小编就带大家来看看动漫制作要掌握哪些技巧?一、动漫作品首先完成草图设计和原型制作。设计草图要有目的、有对象、有步骤、要形象、要简单、符合实际。设计图要一致性,以保证制作的顺利进行。二、原型制作是根据设计图纸和制作材料,可以是手绘也可以是3d软件创建。在此步骤中,要注意的问题是色彩和平面布局。三、动漫制作制作完成后,加工成型。完成不同的表现形式后,就要对设计稿进行加工处理,使加工的难易度降低,并得到一些基本准确的概念,以便于后续的大样、准确的尺寸制定。四、

  5. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  6. 键删除后 ruby​​ 哈希内存泄漏 - 2

    你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p

  7. ruby-on-rails - HTTParty 的内存问题和下载大文件 - 2

    这会导致Ruby出现内存问题吗?我知道如果大小超过10KB,Open-URI会写入TempFile。但是HTTParty会在写入TempFile之前尝试将整个PDF保存到内存吗?src=Tempfile.new("file.pdf")src.binmodesrc.writeHTTParty.get("large_file.pdf").parsed_response 最佳答案 您可以使用Net::HTTP。参见thedocumentation(特别是标题为“流媒体响应机构”的部分)。这是文档中的示例:uri=URI('http://e

  8. 建模分析 | 平面2R机器人(二连杆)运动学与动力学建模(附Matlab仿真) - 2

    目录0专栏介绍1平面2R机器人概述2运动学建模2.1正运动学模型2.2逆运动学模型2.3机器人运动学仿真3动力学建模3.1计算动能3.2势能计算与动力学方程3.3动力学仿真0专栏介绍?附C++/Python/Matlab全套代码?课程设计、毕业设计、创新竞赛必备!详细介绍全局规划(图搜索、采样法、智能算法等);局部规划(DWA、APF等);曲线优化(贝塞尔曲线、B样条曲线等)。?详情:图解自动驾驶中的运动规划(MotionPlanning),附几十种规划算法1平面2R机器人概述如图1所示为本文的研究本体——平面2R机器人。对参数进行如下定义:机器人广义坐标

  9. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  10. 网站日志分析软件--让网站日志分析工作变得更简单 - 2

    网站的日志分析,是seo优化不可忽视的一门功课,但网站越大,每天产生的日志就越大,大站一天都可以产生几个G的网站日志,如果光靠肉眼去分析,那可能看到猴年马月都看不完,因此借助网站日志分析工具去分析网站日志,那将会使网站日志分析工作变得更简单。下面推荐两款网站日志分析软件。第一款:逆火网站日志分析器逆火网站日志分析器是一款功能全面的网站服务器日志分析软件。通过分析网站的日志文件,不仅能够精准的知道网站的访问量、网站的访问来源,网站的广告点击,访客的地区统计,搜索引擎关键字查询等,还能够一次性分析多个网站的日志文件,让你轻松管理网站。逆火网站日志分析器下载地址:https://pan.baidu.

随机推荐