从Java垃圾回收机制窥探内存优化

回答一个疑问

这篇文章讲的是Java的JVM的垃圾回收机制,但是Android使用的虚拟机是Dalvik或者ART,那么下面讲的垃圾回收机制是否适用于Android呢?

答案是,Yes,是可以类比的。

(增补)
文章末尾有人提出了质疑: JVM 的内存模型和 Android 虚拟机是区别的?

答案:是的,Android基于寄存器,jvm基于堆栈,本文其实避免了这样的探讨,那是因为在逻辑上它们其实没有太大区别,Android作为移动操作系统基于寄存器,可以极大提高它的访存速度,从而提高它的程序运行速度,堆栈访存就慢些。这是最大的区别,在这里做出说明。

其他的问题我也在评论里做出了回应,有任何问题都可以在下面探讨,如果本文有重大漏洞,我会卸载勘误
一栏中,大家可以关注一下。

开始

作为Android工程师,我看过很多关于Android内存泄漏的相关优化的文章,其中大部分都是告诉你该怎么做,做哪些,列一些具体的措施。很少解释为什么要这么做,即使解释,也只是一笔带过。

今天,我就以内存回收为突破口,向大家解释从底层到上层,是如何配合完成内存回收的。我们就从Java程序运行时的内存区域开始吧。

运行时内存区域,指的是当你的程序被JVM加载进来执行的时候,内存是怎么分配的。

下面,就是Java程序运行时的内存模型

这里写图片描述
如上图所示,当你的Java字节码执行起来的时候,虚拟机就会它所管理的内存大致分成这五个部分,把你的代码,产生的对象等等分别扔到这五个框框里:
方法区:用于存储类信息,常量,静态变量,编译后的代码等等这些
本地方法栈:用于为本地方法的执行提供服务(可以不了解)
虚拟机栈:是虚拟机执行Java方法的重要内存模型。内部有一个局部变量表,这个表存储了对象引用(这个局部变量表常被我们成为栈)。
堆:存储对象实例的区域(比如 A a=new A(),那么 a这个引用就保存在上面的局部变量表中,而new A() 的这个对象就放在堆中)
程序计数器:用来记录当前线程执行的字节码的地址,指示执行引擎执行代码。
执行引擎:哎呀卧槽,刚才执行到哪一步来着?
程序计数器:傻逼。
其实上面那五个区域,和这篇文章关系最紧密的时堆和虚拟机栈中的局部变量表(也就是我们常说的栈),栈中主要保存了对象的引用,堆中保存了实际的对象,因此,实际上堆占了整个程序运行内存的大头,因此,内存回收就发生在堆中。

当程序运行时,然后躲在暗处的那个饥渴难耐端的垃圾回收机制(GC)就马上跳出来了。虎视眈眈的盯着堆中的对象,专门找那些“落单”的对象….

那么,GC是怎么知道哪个对象“落单”了呢,答案是GC Roots引用链。

通过这个引用链往下搜索,所有在这些链条上的对象都拿到了免死金牌,而其余就是落单的,它们随后就会被GC回收。
关于GC引用链无论怎么说,都很难想象,那没关系,我来画一画就好了。
这里写图片描述

GC程序从栈顶开始一直找到栈底,寻找每个对象引用所对应的对象实例,然后在实例中寻找是否有指向其他对象的引用,若有,继续找(这一部分并没有画出,但是也是重点),没有,则回到栈中,继续往栈底搜索。
当然,GC不止会在栈中寻找引用,还会在静态存储区(存储静态变量的信息存储在方法区)中寻找引用,(因为有的堆中的对象在栈中没有引用,它的引用在静态存储区,类似于 static A a =new A() )
当那些待回收的对象被标记之后,GC就会开始回收对象释放内存。GC的回收算法有很多种,一般虚拟机配合多种内存回收算法来实现内存的高效回收,但是这些和我们其实关系不大,因此可以略过。

好了,我们终于把Java内存回收的机理讲完了,那么内存优化背后的机理也基本被我们扒开了:

不再使用对象时,将引用置空,那么GC顺着栈或者静态存储区中的引用就找不到堆中对应的对象,那么这个对应的对象就会被回收。
尽量不要在生命周期较长(程序执行期间可能都不会被收回)的对象实例中引用其他的不必要的占内存较大的对象实例
很多Android优化场景,基本围绕了一个点:

Android中Activity,context,bitmap等占据较大的内存空间对象,在不用的时候,一定保证当前对象的直接引用和间接引用全部被置为空。内存才能被释放。(重点注意多线程和网络请求这种不可控的场景)
所以Java内存优化一个最根本的准则,就是努力使你的程序适配Java的GC机制。

后记

最近下定决心要涉足新领域,因此给自己定下目标,从这一篇开始,要系统的归纳自己所学的知识技术以及积攒的经验,以文章的方式产出。内容主要以Java+Android相关为主,以JS+React-native次之,然后是一些基于python的有意思的项目(是大学里写的,会重新整理)。

大家放心,我的文章会保证一贯的简单友好,至少同一个层次的知识,我的文章能比别人更加友好,我有这样的信心。

回到这篇文章本身,其实在重新整理的时候,我已经发现最近掘金上已经有人把Android优化整理了一个系列文章,我觉得写的很不错,在这里也可以推荐给大家@anly_jun: android优化系列。

当然,如果你比较欣赏我的文章风格,欢迎关注我,我会在保证文章质量的前提下,提高写作速度的。

共勉

勘误

暂无

参考

《深入理解Java虚拟机》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章