程序员人生 网站导航

Android gc垃圾回收研究学习

栏目:综合技术时间:2015-04-13 08:53:07

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

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利用在底层都会对应1个独立的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。并把所有存活下来的对象转移到其中1个survivor区。
(3)Minor GC一样会检查存活下来的对象,并把它们转移到另外一个survivor区。这样在1段时间内,总会有1个空的survivor区。

Old Generation

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

Permanent Generation:

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

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

新生代的GC:

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

旧生代的GC:

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

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

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

(1)援用计数搜集器

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

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

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

(2)跟踪搜集器

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

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

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

gc的缘由(Log释义)

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

GC_CONCURRENT A concurrent garbage collection that frees up memory as your heap begins to fill up. GC_FOR_MALLOC A garbage collection caused because your app attempted to allocate memory when your heap was already full, so the system had to stop your app and reclaim memory. GC_HPROF_DUMP_HEAP A garbage collection that occurs when you create an HPROF file to analyze your heap. GC_EXPLICIT An explicit garbage collection, such as when you call gc() (which you should avoid calling and instead trust the garbage collector to run when needed). GC_EXTERNAL_ALLOC This happens only on API level 10 and lower (newer versions allocate everything in the Dalvik heap). A garbage collection for externally allocated memory (such as the pixel data stored in native memory or NIO byte buffers).

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

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐