垃圾回收
-
如何判定对象为垃圾对象
- 引用计数法
- 可达性分析法
-
如何回收
- 回收策略
- 标记-清楚算法
- 复制算法
- 标记-整理算法
- 分代收集算法
- 垃圾回收器
- Serial
- Parnew
- CMS
- G1
- 回收策略
如何判定垃圾对象
- 引用计数法:简单,速度慢
每个对象都含有一个引用计数器,当有引用连接到对象时,引用计数器+1,当引用离开作用域或被置为null时-1.当发现某个对象的引用计数为0时就会释放其占用的空间。这种方法对于垃圾回收器而言,定位交互自引用的对象组工作量巨大,而且如果对象间存在循环引用,就可能出现本应该被回收的对象,引用计数器却不为0.
- 可达性分析法
对任何活的对象,一定能追溯到其存活在堆栈或静态存储区域之中的引用,这个引用链可能穿过数个对象层次,由此,如果从堆栈和静态存储区开始,遍历所有的引用,就能找到所有活的对象,对于发现的每个引用必须跟踪它所引用的对象,然后是此对象包含的所有引用,如此反复进行,直到“根源于堆栈和静态存储区的引用“所形成的的网络全部被访问为止。
作为GCRoots的对象
- 虚拟机栈
- 方法区的类属性所引用的对象
- 方法区中常量所引用的对象
- 本地方法栈中所引用的对象
回收策略
- 标记-清除算法
标记-清扫的工作方式同样是从堆栈和静态存储区出发,遍历所有引用,找出所有存活的对象并设置标记,当所有标记工作完成时,没有标记的对象将会被释放,这样剩下的堆空间是不连续的。
- 复制算法
在这种方式下,停止-复制意味着先暂停程序的运行,然后将所有存活的对象从当前堆复制到 另一个堆,没有被复制的全是垃圾,当对象被分配到新堆时,他们是紧凑排列的,就可以按先前的方法 直接分配新空间了。
停止-复制的效率比较低,究其原因,首先要有两个堆,然后在这两个分离的堆之间来回倒腾,从而维护比实际需要多一倍的空间。 一些JVM对此的处理方式是,按需从堆中分配几块较大的内存,复制动作发生在这些大块内存之中。 第二个问题在于复制,程序进入稳定状态后,可能只会产生少量垃圾,尽管如此,复制式回收器仍然把所有内存自一处复制到另一处,这很浪费,为避免此类情况,如果没有新垃圾产生,就会切换到另一种工作模式–标记清扫模式。
- 标记-整理算法
- 分代收集算法
垃圾回收器
-
Parallel Scavenge收集器
- 复制算法
- 多线程收集器
- 可控的吞吐量
- -XX:MaxGCPauseMillis 垃圾收集器最大停顿时间
- -XX:GCTimeRatio 吞吐量大小(0-99)
-
CMS收集器(Concurrent Mark Sweep)
- 工作过程
- 初始标记
- 并发标记
- 重新标记
- 并发清理
- 优点
- 并发收集
- 低停顿
- 缺点
- 占用大量CPU资源
- 无法处理浮动垃圾
- 空间碎片
- Concurrent Mode Failure
- 工作过程
-
G1收集器
- 优点
- 并行与并发
- 分代收集
- 空间整合
- 可预测的停顿
- 步骤
- 初始标记
- 并发标记
- 最终标记
- 筛选回收
- 优点