JVM GC算法

553 阅读3分钟

可达性算法 - 对象生死判定算法

Java通过可达性分析来判定对象是否还被引用。什么是可达性分析呢:

Java会从一些叫做GCRoot的对象开始向下遍历,可以遍历到的对象,就是被引用的对象,不可以遍历到的对象就是不可达对象,就是死掉的对象了:

在图上可以看到,从GCRoot开始,蓝色部分的对象都可以被遍历到,儿灰色部分,即使 Object A 可以遍历到 Object B 和Object C,但是却没有了GCRoot 引用,所以就属于不可达的死亡对象了。

以下几种对象可以作为GC Root:

  • 虚拟机栈中的引用对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用对象
  • 本地方法栈中JNI引用对象

GC回收垃圾的算法有三种:

  • 标记-清除算法
  • 复制算法
  • 标记-整理算法

1. 标记清除算法

分为两个阶段:标记(mark)、清除(sweep)

注意:
Collector在进行标记和清除阶段时会将整个应用程序暂停(,如果不停止,此时如果存在新产生的对象,这个对象是树根可达的,但是没有被标记(标记已经完成了),会清除掉。等待标记清除结束后才会恢复应用程序的运行,这也是Stop-The-World这个单词的来历。

缺点:

  • 递归效率低性能低
  • 释放空间不连续容易导致内存碎片
  • 会停止整个程序运行

2. 复制算法

为了解决效率问题,有了复制算法,这种算法将内存分成相同大小的两块:活动区、空闲区(保留区)

其实并不是非要等比划分内存的,大部分对象死的很早Hotspot是划分了三块区域,一块大的两块小的,大的叫Eden,小的叫survivor,大小比例为8:1。清理时将Eden和survivor中存活的对象复制到另一块survivor内存上,然后,清理掉用过的两块内存,下次再用。当survivor不够大的时候,需要依靠新的分配担保去拓展空间。

缺点:
速度快但耗费空间,假定活动区域全部是活动对象,这个时候进行交换的时候就相当于多占用了一倍空间,但是没啥用。

3. 标记-整理算法

综合复制和标记算法,整理算法会把有用的存活对象一端移动,这样避免了复制算法浪费那么多内存,也不会像普通标记回收算法一样导致内存碎片过于严重。

JVM垃圾回收分代收集算法

将java堆内存分成老年代,新生代。新生代死亡比较快,老年代比较持久。
所以一般新生代区域使用复制方法,只需要复制几个就可以了,老年代比较持久,所以一般用标记清除,或标记整理来回收。



文章转载自:Java的GC如何玩弄对象——GC的几种算法