普通java虚拟机和dalvik在gc上的异同

来源:互联网 发布:直男癌 知乎 编辑:程序博客网 时间:2024/04/30 19:36
普通java虚拟机gc方面的资料挺多的,他有很多不同的算法,这个简单列一下:

引用计数(Reference Counting
虚拟机会根据对象的被引用情况来改变其引用计数,当某对象的引用计数为0时便会被收回。


追踪(Tracing)
追踪回收法会用到JVM维护的对象引用图,从跟节点开始追踪,遇到的对象打上印记。当整个追踪过程结束,未被标记的对象就是无法到达的,是可以被回收的,在某个适当的时候会被回收。


压缩(Compacting)

压缩回收算法把堆中的活动对象移动到堆的一端,这样就结果就是在堆的另外一端留出了一个大的空闲区,也就相当于压缩掉了垃圾对象和活动对象之间的碎片。压缩回收算法要求所有被移动对象的引用也要同步更新,指向新的移动后的位置。这一切都是在对程序员透明的情况下,由JVM来做的。
该算法不仅回收了堆里的垃圾,还整理了内存碎片。



拷贝(Coping)
拷贝回收算法一般把堆分成两个大小的区域,任何时刻只有一个区域在使用。对象在同一个区域内分配/释放,直到这个区域不能再被分配。此时当前正在运行的程序被中断,扫描使用中的的区域,遇到活动对象就把它拷贝到另外的哪个区域,知道没有活动对象,此时被中止的程序再次运行,而使用的堆是拷贝活动对象到的区域,完成两个区域的转换。拷贝回收算法也要求所有被拷贝对象的引用也要同步更新,指向新的拷贝后的位置。
拷贝算法也是实现了对垃圾的回收和碎片的整理。但是这个算法代价也很高,需要堆空间两倍大的内存;因为要停止当前运行程序进行内存整理,也需要耗费很长的时间,效率很低。分代回收算法可以减缓这种代价。


分代(Generational)
该算法把对象按他们的寿命进行分组,优先回收年轻的对象。把堆按代分组,每组称做一代。子代里的对象可以转到高一级的代里,如果一个对象经过多次收集仍然存活,把它移到高一级的代的堆里,减少再次扫描它的次数。

火车(Train)算法

Train算法在堆中老的代和年轻的代之间创建一个新区域。这些堆区域划分为“火车”,每个火车又分为一系列的车厢。每个火车车厢组成单独的一代,这意味着不但要跟踪老到年轻的引用,而且还要跟踪从老的火车到年轻的火车以及老的车厢到年轻的车厢的引用。

回收可以针对车也可以针对车厢。回收的时候会把被回收的火车/车厢内被引用的对象都转到其它车/车厢中,剩下的就是垃圾,可以整个火车/车厢的回收了。这个算法提供了对堆空间限定时间内的渐进式回收,可以用在嵌入式实时环境。

自适应(Adaptive)算法
垃圾回收算法在不同的情况下,工作表现也不同。自适应算法通过监视堆的情形,相应的调整垃圾回收算法。

Dalvik VM则不同,在进行GC的时候会单独申请一块空间,以位图的形式来保存整个堆上的对象的标记,在GC结束后就释放该空间。 
在标记阶段,从根集合开始,沿着对象用的引用进行标记直到没有更多可标记的对象为止。标记结束后,被标记的就是活着的对象,没被标记到的就是“垃圾”。在清除阶段,Dalvik VM并不直接对堆做什么操作,而是在一个记录分配状况的位图上把被认为是垃圾的对象所在位置的分配标记清零。为了不让这个位图太大,位图中并不是每一位对应到堆上的一个字节,而是对应到一块固定大小的空间。为此,堆空间的分配也是有一定对齐的。 
只进行标记-清除,在经过多次GC后可能会使堆被碎片化。Android所实现的libc(称为Bionic)对这种情况有特别的实现,可以避免碎片化问题。 

原创粉丝点击