针对方法区和堆内存
如何判断java堆中内存是否存活:
- 引用计数法:给对象添加引用计数器,被引用时计数器值加1,失效时计数器值减1。很难解决对象之间相互循环引用的问题。
- 可达性分析算法(一般用这种方法):
“GC Roots”对象(起始点)———————向下搜索
GC Roots包括:虚拟机栈引用的对象;方法区中类静态属性引用的对象;方法区中常量引用的对象;本地方法栈引用的对象
引用:
强引用: 类似“Object obj = new Object()”,只要引用存在,永远不会被回收
软引用;弱引用;虚引用
堆中垃圾回收过程:
可达性算法判断是否有引用————第一次标记并筛选(是否执行finalize()方法)————没必要执行则移到“即将回收”的集合
方法区回收:废弃常量(和堆中差不多)和无用类
垃圾回收算法简介
-
标记—清除算法:首先标记需要回收的对象,标记完成后统一回收。
问题:1.效率低;2.产生大量不连续的内存碎片 -
复制算法(商业虚拟机使用这种算法回收新生代):将内存分为两块,其中一块用完后,将存活的对象复制到另一块上。优点:运行高效,内存分配时不用考虑内存碎片;缺点:内存变成了原来的一半。p70详细介绍。
-
标记—整理算法(回收老年代):前期标记,标记后让所有存活对象向一端移动,再清理掉端边界以外内存
-
分代收集算法:根据对象存活周期不同分为新生代和老年代
HotSpot算法实现
- 枚举根节点:通过OopMap数据结构实现,在类加载完成后把对象内什么偏移量上是什么类型数据计算出来
- 安全点:抢先式中断:首先中断所有线程,发现不在安全点上的线程,让它跑到安全点,不使用该方法。主动式中断:需要中断时,设置一个标志,各线程轮询该标志
- 安全区域:引用关系不发生变化的区域。
垃圾收集器
-
Serial收集器:运行在Client虚拟机是一个好选择,收集新生代,简单高效,单线程
-
ParNew收集器:多线程,其他和Serial差不多。运行在Severt模式下首选。
-
Parallel Scavenge收集器:关注的吞吐量。可以设置最大垃圾收集停顿时间参数和设置吞吐量大小的参数。
-
Serial Old收集器: Serial收集器老年代版本。
-
Parallel Old收集器:Parallel Scavenge收集器老年代版本。
-
CMS收集器:获取最短回收停顿时间为目标。
初始标记—并发标记—重新标记—并发清除
缺点:对CPU敏感;无法收集浮动垃圾;使用标记—清除算法的缺点 -
G1收集器:
并行并发;分代收集;空间整合;可预测的停顿
初始标记—并发标记—最终标记—筛选回收