书到用时方恨少,事非经过不知难!本文参考《深入理解JVM》周至明著。由于写作水平和写作时间有限,本中存在不妥之处,还请大家多多留言。
思想:创建对象时并给其添加一个引用计数器,当某一地方引用它时,计数器值+1,当引用失效时,计数器值-1;任何计数器为0的对象就不可能再被使用。
缺点:难解决对象之间相互循环引用的问题。
思想:通过一系列 “GC Roots” 对象作为起始点,从这些节点向下搜索,搜索经过的路径称为引用链(Reference Chain),当某一个对象到 GC Roots 没有任何引用链连接时,则证明对象不可能再被引用。
虚拟机栈中引用对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI(一般指Native方法)引用的对象
过程:分为2个阶段,标记和清除。首先标记处所有需要清理的对象,标记完成之后,统一回收被标记的所有对象。
不足:
工作如下图所示
基本思想:将可用内存按容量分为大小相等2块(用A、B代指),每次先使用A,当A使用完了,就A现存活对象复制到B中,然后一次将A的内存空间清空。
优点:不考虑内存碎片等复杂情况。
缺点:将内存缩小为原来一半。
工作如下图所示:
基本思想:先标记完所有可回收对象,然后让存活对象向一端移动,最后清理掉剩下的内存。
“标记-整理算法”如下图所示:
当前商业虚拟机垃圾收集都采用“分代收集”(Generational Collection)算法,根据对象存活周期不同划分为几块;一般将其分为新生代和老年代。
新生代特点:每次垃圾收集时都有大批对象死去,只要少量存活。(采用复制算法)
老年代特点:对象存活率高、没有额外空间对它进行分配担保,就采用“标记-清理”或“标记-整理”算法来进行回收。
分配担保机制:某一空间内存(譬如:新生代)不够时,需要依赖另一空间(譬如:老年代)进行担保。如生活中去银行借款,需要一个担保人一样。
在安全点/安全域中使用OopMap结构完成根节点枚举。
在HotSpot 实现根节点枚举时,遇到2个问题:1、数据一致性:在判定对象过程中必须保证对象引用关系不变。2、消耗时间多:逐个检查引用。
解决办法:通过使用一组称为OopMap的数据结构,在类加载、编译过程中确定偏移量及对应的数据类型,在特定位置记录栈和寄存器中哪些位置是引用。
一般在方法调用、循环跳转、异常跳转等“长时间执行”的地方,才会产生安全点(Safepoint)。即指上面提到的“特定位置”。
在一段代码中,引用关系不会发生变化。
以垃圾收集线程与用户线程为例:
并行(Parallel):多条垃圾收集线程并行工作。
并发(Concurrent):用户线程与垃圾收集线程同时进行。
下图展示7种收集器,2个收集器之间存在连线,表名可搭配使用。
特点:单线程的收集器,在它进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束。
适用场景:JVM 运行在Client模式下的默认新生代收集器。
特点:使用多条线程进行垃圾收集。
适用场景:Service模式下的JVM中首选的新生代收集器。
特点:新生代收集器;一个可控制的吞吐量。即吞吐量=运行用户代码时间/(垃圾收集时间+运行用户代码时间)。
GC自适应的调节策略(GC Ergonomics):虚拟机根据当前系统运行情况收集性能监控信息,动态调整参数。
使用“标记-整理”算法,单线程收集器。
使用多线程和“标记-整理”算法
目标:获取最短回收停顿时间。基于“标记-清除”算法。
在JDK1.7之后采用此收集器,用于服务端应用的垃圾收集器。
特点: