JAVA 垃圾收集时如何判断一个对象是否存活?一种做法是引用计数,但这种做法不能解决循环引用的问题;令一种做法是根集搜索,从根集出发搜索所有可达对象,根集的内容包括所有在栈中的引用,在方法区中的静态属性引用和常量引用,等等。
垃圾收集的算法包括:
- 标记清除算法:留下内存碎片;
- 复制算法:需要划分 Eden 空间和 Survivor 空间,清除 Eden 空间时将存活对象拷贝到 Survivor 空间,万一 Survivor 空间不够需要由老年代担保;
- 标记整理算法:和标记清除类似,但存活对象向空间的一段整理,剩余的令一端为空闲;
- 分代收集:新生代用复制算法,老年代用标记真理算法;
垃圾收集器:
- Serial 新生代,复制算法,单线程垃圾收集,收集时停止用户线程执行;
- ParNew 新生代,复制算法,多线程并行垃圾收集,收集时停止用户线程执行;
- Parallel Scanvenge 新生代,复制算法,多线程并行垃圾收集,停止用户线程执行,实现可控制的吞吐量(吞吐量优化);
- Serial Old 老年代,单线程,标记整理算法,收集时停止用户线程执行;
- Parallel Old 老年代,多线程,标记整理算法,收集时停止用户线程执行;
- CMS, concurrent mark-swap,老年代,标记清除算法,多线程并行收集,与用户线程并发执行,实现垃圾收集最小停顿;缺点:CPU敏感、无法处理浮动垃圾、产生空间碎片、有时要触发 Full GC;
垃圾收集可配置策略:
- 对象优先在 Eden 分配
- 大对象直接进入老年代;
- 长期存活对象进入老年代对象的存活期门槛;
- 在 Minor GC 发生时,预测老年代空间是否能满足担保要求,如果不满足担保要求:如果允许担保失败,则最坏情况为 Minor GC ->担保失败 -> Full GC;若不允许担保失败,则直接 Full GC;
参考文献《深入理解JAVA虚拟机:JVM高级特性与最佳实践》,周志明