5

Android gc垃圾回收研究学习

 3 years ago
source link: https://blog.csdn.net/eclipsexys/article/details/45170583
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

尊重个人劳动成果,转载请注明出处:http://blog.csdn.net/hnulwt/article/details/44903331 
文中很多内容说到了JVM,我想通过研究学习JVM来达到认识DVM的目的。为了严谨,查询了一下

JVM和DVM的不同点

1、Dalvik 和标准 Java 虚拟机(JVM)的首要差别

Dalvik 基于寄存器,而 JVM 基于栈。基于寄存器的虚拟机对于更大的程序来说,在它们编译的时候,花费的时间更短。

2、Dalvik 和 Java 字节码的区别

Dalvik执行.dex格式的字节码,而JVM执行.class格式的字节码。android程序编译完之后生产.class文件,还有通过aapt工具生成的R.class等,然后dx工具会把.class文件处理成.dex文件,最终资源文件和.dex文件等打包成.apk文件。

3、Dalvik和Java运行环境的区别

Dalvik主要是完成对象生命周期管理,堆栈管理,线程管理,安全和异常管理,以及垃圾回收等等重要功能。 
Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。

通过以上可以看出,这些不同点并不影响对DVM—gc相关的学习,所以我通过研究JVM相关的垃圾回收机制,来学习Android gc相关内容,如果文中有什么不对的地方,麻烦大家指出,共同学习,共同进步。

粗略的说:GC(Garbage Collection)动态回收无任何引用的对象占据的内存空间。GC通过确定对象是否被活动对象引用来确定是否收集该对象。 
但是理解以上几句话我们可能需要了解以下知识。

JVM内存模型

这里写图片描述

Young Generation

图中的Eden + S0 + S1 
Eden:存放新生的对象 
Survivor Space:S0、S1 有两个,存放每次垃圾回收后存活的对象 
(1)大多数新建的对象都位于Eden区。 
(2)当Eden区被对象填满时,就会执行Minor GC。并把所有存活下来的对象转移到其中一个survivor区。 
(3)Minor GC同样会检查存活下来的对象,并把它们转移到另一个survivor区。这样在一段时间内,总会有一个空的survivor区。

Old Generation

图中的Old Memory 主要存放应用程序中 长期存活的对象和经过多次Minor GC后依然存活下来的对象。通常会在老年代内存被占满时进行垃圾回收。老年代的垃圾收集叫做Major GC。Major GC会花费更多的时间。

Permanent Generation:

存放方法区,方法区中有 要加载的类信息、静态变量、final类型的常量、属性和方法信息。

JVM分别对新生代和旧生代采用的两种垃圾回收机制?

新生代的GC:

新生代通常存活时间较短,因此基于Copying算法来进行回收,所谓Copying算法就是扫描出存活的对象,并复制到一块新的完全未使用的空间中,对应于新生代,就是在Eden和FromSpace或ToSpace之间copy。新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。当连续分配对象时,对象会逐渐从eden到survivor,最后到旧生代。

旧生代的GC:

旧生代与新生代不同,对象存活的时间比较长,比较稳定,因此采用标记(Mark)算法来进行回收,所谓标记就是扫描出存活的对象,然后再进行回收未被标记的对象,回收后对用空出的空间要么进行合并,要么标记出来便于下次进行分配,总之就是要减少内存碎片带来的效率损耗。

如何判断对象是否可以被回收?

两种常用的方法是引用计数和对象引用遍历。

(1)引用计数收集器

引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象(不是引用)都有一个引用计数。当一个对象被创建时,且将该对象分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象+1),但当一个对象的某个引用超过了生命周期或者被设置为一个新值时,对象的引用计数减1。任何引用计数为0的对象可以被当作垃圾收集。当一个对象被垃圾收集时,它引用的任何对象计数减1。

优点:引用计数收集器可以很快的执行,交织在程序运行中。对程序不被长时间打断的实时环境比较有利。

缺点: 无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0.

(2)跟踪收集器

现在大多数JVM采用对象引用遍历。对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。在对象遍历阶段,GC必须记住哪些对象可以到达,以便删除不可到达的对象,这称为标记(marking)对象。

下一步,GC要删除不可到达的对象。删除时,有些GC只是简单的扫描堆栈,删除未标记的未标记的对象,并释放它们的内存以生成新的对象,这叫做清除(sweeping)。这种方法的问题在于内存会分成好多小段,而它们不足以用于新的对象,但是组合起来却很大。因此,许多GC可以重新组织内存中的对象,并进行压缩(compact),形成可利用的空间。

为此,GC需要停止其他的活动活动。这种方法意味着所有与应用程序相关的工作停止,只有GC运行。结果,在响应期间增减了许多混杂请求。另外,更复杂的 GC不断增加或同时运行以减少或者清除应用程序的中断。有的GC使用单线程完成这项工作,有的则采用多线程以增加效率。

gc的原因(Log释义)

在官方文档上查了一下,gc reason有如下5个:

GC_CONCURRENT、GC_FOR_MALLOC都是比较常见的gc原因。可以通过运行程序在Logcat上查看。 
GC_CONCURRENT当堆要满的时候进行的垃圾收集 
GC_FOR_MALLOC这就是“Stop the World”事件,因为所有的应用线程都会停下来直到操作完成。这时候堆已经满了,你申请分配内存就会触发这种原因的gc。

GC_HPROF_DUMP_HEAP 
在我们创建HPROF文件分析堆内存的时候的gc原因。

GC_EXPLICIT 
当我们显示的调用System.gc()方法,会出现的log。

GC_EXTERNAL_ALLOC 
这个仅仅在API 10 及以下才会出现,我们不需要关注了。

文章部分参考自: 
原文链接: journaldev 翻译: ImportNew.com - 进林 译文链接: http://www.importnew.com/14086.html 
详细介绍Java垃圾回收机制:http://www.cnblogs.com/laoyangHJ/articles/java_gc.html 
百度百科:http://baike.baidu.com/view/1551869.htm


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK