【「内存抖动」?别再吓唬面试者们了行吗】 www.bilibili.com/video/BV1xf…
内存抖动
在程序里,每创建一个对象,就会有一块内存分配给它;每分配一块内存,程序的可用内存也就少一块;当程序被占用的内存达到一定临界程度,GC 也就是垃圾回收器(Garbage Collector)就会出动,来释放掉一部分不再被使用的内存。Android 里的 View.onDraw() 方法在每次需要重绘的时候都会被调用,这就意味着,如果你在 onDraw() 里写了创建对象的代码,在界面频繁刷新的时候,你就也会频繁创建出一大批只被使用一次的对象,这就会导致内存占用的迅速攀升;然后很快,可能就会触发 GC 的回收动作,也就是这些被你创建出来的对象被 GC 回收掉。垃圾内存太多了就被清理掉,这是 Java 的工作机制,这不是问题。问题在于,频繁创建这些对象会造成内存不断地攀升,在刚回收了之后又迅速涨起来,那么紧接着就是又一次的回收,对吧?这么往复下来,最终导致一种循环,一种在短时间内反复地发生内存增长和回收的循环。
这种循环往复的状态就像是水波纹的颤动一样,它的专业称呼叫做 Memory Churn,Android 的官方文档里把它翻译做了内存抖动。所以内存抖动其实并不是我们的内存在整体地进行摇晃这样神奇的事情,
内存的回收虽然很快,时间成本很低,但终究是有时间成本的。一两次内存回收不容易被用户察觉,但多次内存回收行为集中在短时间内爆发,这就造成了比较大的界面卡顿的风险。这也是为什么 Android 在官方文档和 Android Studio 里都建议我们尽量避免在 onDraw() 里创建对象。
同样的道理,不只是在 onDraw(),在次数比较大的循环里创建对象,同样会导致内存抖动。不过因为在实践中,我们在 onDraw() 里创建的对象往往是绘制相关的对象,而这些对象又经常会包含通往系统下层的 Native 对象的引用,这就导致在 onDraw() 里创建对象所导致的内存回收的耗时往往会更高,直白地说就是——界面更卡顿。
另外呢内存抖动有时候也会抖着抖着就变成内存溢出了,这就是更严重的情况,因为内存溢出的直接结果就是软件崩溃。
View.onDraw() 方法每次重绘的时候都需要被调用,如果在 onDraw() 里面创建对象会导致频繁触发内存回收。onDraw() 里创建的对象往往是和绘制相关的对象,而这些对象又经常包含通往系统下层的 native 对象的引用,这就导致在 onDraw() 里创建对象所导致的内存回收的耗时会更高。