object(stdClass)#33 (2) { ["docs"]=> array(0) { } ["count"]=> int(0) } GC回收机制,GC算法。GC垃圾回收 - 爱码网

java中,GC的主要对象是堆空间和永久区。而我们更多讨论的是堆空间这部分。

GC回收机制,GC算法。GC垃圾回收

                 堆的内存分配图

GC的工作目的很明确:新生成的对象,都放在Eden中;当Eden充满时(小孩太多 了),GC将开始工作,首先停止应用程序的运行,开始收集垃圾。在堆中,找到已经无用的对象,并把这些对象占用的空间收回使其可以重新利用.大多数垃圾回收的 算法思路都是一致的:把所有对象组成一个集合,或可以理解为树状结构,从树根开始找,只要可以找到的都是活动对象,如果找不到,这个对象就是凋零的昨日黄 花,应该被回收了。

GC算法:引用计数法,标记清除,标记压缩,复制算法,主要是这四种。

一.引用计数法的原理:对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1,当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,则对象A就不可能再被使用。

缺陷:引用和去引用伴随加法和减法,影响性能很难处理循环引用。所以java中并没有使用引用计数法。

二.标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象,可达对象可理解为被引用的对象,因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。如图中,标记阶段先标记,清除阶段,清除未标记为引用的对象。
GC回收机制,GC算法。GC垃圾回收
                图1

三.标记-压缩算法适合用于存活对象较多的场合,如老年代一般使用这种算法,对老年代垃圾回收又叫MajorGC。它在标记-清除算法的基础上做了一些优化。和标记-清除算法基本思想一样,标记-压缩算法也首先需要从根节点开始,对所有可达对象做一次标记。但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端,就是移到一边。之后,清理边界外所有的空间。如图2

GC回收机制,GC算法。GC垃圾回收

                                                                            图2

四。复制算法:与标记-清除算法相比,复制算法是一种相对高效的回收方法,不适用于存活对象较多的场合 如老年代。复制算法一般使用在新生代,对新生代进行垃圾回收又叫做MinorGC(他和老年代不冲突)。将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收

GC回收机制,GC算法。GC垃圾回收

                     图3

如上图3,复制算法执行后,先把存活对象复制到另一块区域,然后对之前区域进行一次清理,第一张图所画的A,B空间,把存活的对象由A复制到B,然后清理A区域,再把B区域存活对象复制到A,来回复制,每被复制一次,就会加一计数,当到达十五次(,默认应该是十五次,可以设置)之后,就进入了老年代,如下图4,还有一部分对象就是大对象,因为占得空间比较大,复制比较占空间,会直接进入老年代。

所以:少量对象存活,适合复制算法。大量对象存活,适合标记清理或者标记压缩。

GC回收机制,GC算法。GC垃圾回收

补充名词:

1.top-The-World:多半由于GC引起的,Java中一种全局暂停的现象,全局停顿,所有Java代码停止。native代码可以执行(但不能和JVM交互)。Jvm处于挂机状态,当然Dump,线程死锁检查,堆Dump,也是有可能引起全局暂停的现象,但多数还是GC引起。

2.可触及的对象:从根节点可以触及到这个对象。

3.不可触及的对象:在finalize()调用后,可能会进入不可触及状态,不可触及的对象不可能复活,可以回收。

4.可复活的对象:一旦所有引用被释放,就是可复活状态,因为在finalize()中可能复活该对象。

GC时为什么会有全局停顿?

类比在聚会时打扫房间,聚会时很乱,又有新的垃圾产生,房间永远打扫不干净,只有让大家停止活动了,才能将房间打扫干净。

注意事项:

1.eden满了,触发young GC

2.young GC2件事:一,去掉一部分没用的object;二,把老的还被引用的object发到survior里面,等下几次GC以后,survivor再放到old里面。

3.当老年代满了,触发full GCfull GC很消耗内存,把oldyoung里面大部分垃圾回收掉。这个时候用户线程都会被block

4.young generation比例越大,不一定最好。将young的大小设置为大于总堆大小的一半时会造成效率低下。如果设置得过小,又会因为young generation收集程序不得不频繁运行而造成瓶颈。

5.sun 的文档说明中,对JVM堆的新域,是采用coping算法,该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。






相关文章: