可达性算法 - 对象生死判定算法
Java通过可达性分析来判定对象是否还被引用。什么是可达性分析呢:
Java会从一些叫做GCRoot的对象开始向下遍历,可以遍历到的对象,就是被引用的对象,不可以遍历到的对象就是不可达对象,就是死掉的对象了:
在图上可以看到,从GCRoot开始,蓝色部分的对象都可以被遍历到,儿灰色部分,即使 Object A 可以遍历到 Object B 和Object C,但是却没有了GCRoot 引用,所以就属于不可达的死亡对象了。
以下几种对象可以作为GC Root:
- 虚拟机栈中的引用对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用对象
- 本地方法栈中JNI引用对象
GC回收垃圾的算法有三种:
- 标记-清除算法
- 复制算法
- 标记-整理算法
1. 标记清除算法
分为两个阶段:标记(mark)、清除(sweep)
注意:
Collector在进行标记和清除阶段时会将整个应用程序暂停(,如果不停止,此时如果存在新产生的对象,这个对象是树根可达的,但是没有被标记(标记已经完成了),会清除掉。等待标记清除结束后才会恢复应用程序的运行,这也是Stop-The-World这个单词的来历。
缺点:
- 递归效率低性能低
- 释放空间不连续容易导致内存碎片
- 会停止整个程序运行
2. 复制算法
为了解决效率问题,有了复制算法,这种算法将内存分成相同大小的两块:活动区、空闲区(保留区)
缺点:
速度快但耗费空间,假定活动区域全部是活动对象,这个时候进行交换的时候就相当于多占用了一倍空间,但是没啥用。
3. 标记-整理算法
综合复制和标记算法,整理算法会把有用的存活对象一端移动,这样避免了复制算法浪费那么多内存,也不会像普通标记回收算法一样导致内存碎片过于严重。
JVM垃圾回收分代收集算法
将java堆内存分成老年代,新生代。新生代死亡比较快,老年代比较持久。
所以一般新生代区域使用复制方法,只需要复制几个就可以了,老年代比较持久,所以一般用标记清除,或标记整理来回收。
文章转载自:Java的GC如何玩弄对象——GC的几种算法