调皮的内存抖动?前生今世及App解决卡顿慢

3,653 阅读7分钟

内存抖动

·内存抖动是指内存频繁地分配和回收,而频繁的gc会导致卡顿,严重时和内存泄漏一样会导致OOM。

注意内存抖动为什么会造成OOM这关系到Java的垃圾回收。

造成的原因

主要是频繁(很重要)在循环里创建对象

  • 1、导致大量对象在短时间内被创建,由于新对象是要占用内存空间的而且是频繁,如果一次或者两次在循环里创建对象对内存影响不大,不会造成严重内存抖动这样可以接受也不可避免

  • 2、频繁的话就很内存抖动很严重

简单的提一下垃圾回收机制

垃圾回收

在对对象进行回收前需要对垃圾进行采集,不同的虚拟机实现可能使用不同的垃圾收集算法,不同的收集算法的实现也不尽相同。不同的算法各有各的优劣势。

常用的收集算法有:

1、标记-清除算法 Mark-Sweep

和他的名字一样,算法分为标记和清除两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收被标记的对象。

2、复制算法 Copying

“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。

3、标记压缩算法 Mark-Compact

内存抖动为什么会造成 OOM?

首先我们要了解一些垃圾回收机制的前因后果

在对对象进行回收前需要对垃圾进行采集,不同的虚拟机实现可能使用不同的垃圾收集算法,不同的收集算法的实现也不尽相同。不同的算法各有各的优劣势。

常用的收集算法有:

1、标记-清除算法 Mark-Sweep 2、复制算法 Copying 3、标记压缩算法 Mark-Compact

无论是一般的JVM还是DVM,不会只使用一种垃圾收集算法。它会根据内存的划分实现不同的收集算法。

当前商业虚拟机的垃圾收集都采用分代收集算法。分代的垃圾回收策略,是基于不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。

在Java程序运行的过程中,会产生大量的对象,因每个对象所能承担的职责不同所具有的功能不同所以也有着不一样的生命周期,有的对象生命周期较长,比如Android中的Application、启动的Service等;有的对象生命周期较短,比如一些函数内部new出来的String对象。

在不进行对象存活时间区分的情况下,每次垃圾回收都是对整个堆空间进行回收,那么消耗的时间相对会很长,而且对于存活时间较长的对象进行的扫描工作等都是徒劳。因此就需要引入分治的思想,所谓分治的思想就是因地制宜,将对象进行代的划分,把不同生命周期的对象放在不同的代上使用不同的垃圾回收方式。

现在主流的做法是将Java堆被分为

  • 1、新生代
  • 2、老年代;

新生代又被进一步划分为Eden和Survivor区, Survivor由From Space和To Space组成

这样划分的好处是为了更快的回收内存,根据不同的分代执行不同的回收算法;

Android 虚拟机的由来

Java 虚拟机是一个规范,任何实现该规范的虚拟机都可以用来执行 Java 代码。android就是觉得现在使用的jvm用着不爽,由于 Androd 运行在移动设备上,内存以及电量等诸多方面跟一般的 PC 设备都有本质的区别 ,一般的 JVM 没法满足移动设备的要求,所以自己根据这个规范开发了一个Dalvik 虚拟机。

Dalvik虚拟机主要使用标记清除算法,也可以选择使用拷贝算法。这取决于编译时期:

ART 是在 Android 4.4 中引入的一个开发者选项,也是 Android 5.0 及更高版本的默认 Android 运行时。google已不再继续维护和提供 Dalvik 运行时,现在 ART 采用了其字节码格式。

ART 有多个不同的 GC 方案,这些方案包括运行不同垃圾回收器。默认方案是 CMS。

这就是内存抖动为什么会造成 Android App OOM。

检测优化内存抖动

内存抖动在Android Profile中表现为:

内存抖动在Android Profile中表现

关于内存抖动和内存泄漏就到这里了,接下来就说一下Android studio 提供的内存优化方面的工具

**1、利用Alloctions Tracker来进行排查。**前提AndroidStudio版本>=3.0, 在Android Studio中点击memory profiler中的红点录制一段时间的内存申请情况,再点击结束。 Android Studio提供了工具来帮助开发者发现和解决内存抖动和内存泄漏。

2、 Tool - Memory Monitor(用于发现内存抖动及内存泄漏的)

Android Studio中的Memory Monitor可以很好的帮组我们查看程序的内存使用情况。 Memory Monitor:查看整个app所占用的内存,以及发生GC的时刻,短时间内发生大量的GC操作是一个危险的信号(用于发现有没有内存泄漏和严重内存抖动)。

(后面两个是用于定位的内存抖动和内存泄漏发生的具体位置·) Allocation Tracker:使用此工具来追踪内存的分配,前面有提到过。

Heap Tool:查看当前内存快照,便于对比分析哪些对象有可能是泄漏了的.

举个栗子

你需要避免在for循环里面分配对象占用内存,需要尝试把对象的创建移到循环体之外,自定义View中的onDraw方法也需要引起注意,每次屏幕发生绘制以及动画执行过程中,onDraw方法都会被调用到,避免在onDraw方法里面执行复杂的操作,避免创建对象。对于那些无法避免需要创建对象的情况,我们可以考虑对象池模型,通过对象池来解决频繁创建与销毁的问题,但是这里需要注意结束使用之后,需要手动释放对象池中的对象。

下面是避免发生内存抖动的几点建议:

  • 尽量避免在循环体或者频繁调用的函数内创建对象,应该把对象创建移到循环体外。
  • 注意自定义View的onDraw()方法会被频繁调用,所以在这里面不应该频繁的创建对象。
  • 当需要大量使用Bitmap的时候,试着把它们缓存在数组中实现复用。
  • 对于能够复用的对象,同理可以使用对象池将它们缓存起来。

更多阅读

Android性能优化 (1)—— 内存溢出和内存泄漏的介绍

浅谈App的性能优化

Android性能优化之包体压缩,一篇文章教你玩转优化App

BlockCannery-一个强大的Android程序调试工具,轻松帮你找出卡顿

相信自己,没有做不到的,只有想不到的

微信公众号:终端研发部

技术