标签:处理 eal 代码 扫描 root 相等 rri 回收 enc
垃圾回收
如何判定对象为垃圾对象?
引用计数法
可达性分析法
如何回收?
回收的策略
标记-清除算法
复制算法
标记-整理算法
分代收集算法
垃圾回收器
serial
Parnew
Cms
G1
何时回收?
引用计数法
在对象中添加引用计数器,当有地方引用这个对象的时候,引用计数器的值就+1,当引用失效的时候,计数器的值就-1
打印gc信息的参数
-verbose:gc
-xx:+PrintGCDetails
如果堆内存中的对象区域互相引用,而没有对外引用,引用计数器并不为零,即垃圾回收器并不会回收。
1 public class Test { 2 3 private Object instance; 4 5 public static void main(String[] args) { 6 7 Test t1 = new Test(); 8 Test t2 = new Test(); 9 10 t1.instance = t2; 11 t2.instance = t1; 12 13 t1 = null; 14 t2 = null; 15 16 System.gc(); 17 18 } 19 20 }
1 [GC (System.gc()) [PSYoungGen: 1966K->744K(37888K)] 1966K->752K(123904K), 0.0854947 secs] [Times: user=0.00 sys=0.00, real=0.08 secs] 2 [Full GC (System.gc()) [PSYoungGen: 744K->0K(37888K)] [ParOldGen: 8K->628K(86016K)] 752K->628K(123904K), [Metaspace: 2787K->2787K(1056768K)], 0.0128645 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 3 Heap 4 PSYoungGen total 37888K, used 328K [0x00000000d6200000, 0x00000000d8c00000, 0x0000000100000000) 5 eden space 32768K, 1% used [0x00000000d6200000,0x00000000d6252030,0x00000000d8200000) 6 from space 5120K, 0% used [0x00000000d8200000,0x00000000d8200000,0x00000000d8700000) 7 to space 5120K, 0% used [0x00000000d8700000,0x00000000d8700000,0x00000000d8c00000) 8 ParOldGen total 86016K, used 628K [0x0000000082600000, 0x0000000087a00000, 0x00000000d6200000) 9 object space 86016K, 0% used [0x0000000082600000,0x000000008269d1d8,0x0000000087a00000) 10 Metaspace used 2793K, capacity 4486K, committed 4864K, reserved 1056768K 11 class space used 298K, capacity 386K, committed 512K, reserved 1048576K
可达性分析算法
定义 GCRoot ,然后从gcroot 一直向下找,如果找得到,说明对象存活,找不到说明对象可以被回收,向下搜索的路径称为引用链,当一个对象没有任何节点与GCRoot相连接时,就认为这个对象是不可用的。
作GCRoot的对象
虚拟机栈(栈帧中的局部变量表)
方法区的类属性所引用的对象
方法区在常量所引用的对象
本地方法栈中引用对象
标记清除算法
标记出可以回收的对象,清除无用的对象。
效率问题,内存区域会出现越来越多不连续的空间,再分配一个大对象时,寻址问题难以分配,容易再一次进行垃圾回收,影响性能。
空间问题
复制算法
被线程所共享的有堆,方法区。被线程所独享的有栈内存,本地方法栈,程序计数器。
堆内存是垃圾回收主要的一块区域,堆分为新生代和老年代,新生代分为Eden(伊甸园),也是垃圾回收最受关注的区域 ,Survivor(存活区),Tenured Gen,垃圾回收较少关注
为了解决效率问题,一种称为“复制”(Copying)的收集算法出现了,他将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
新生代中的对象98%是“朝生夕死”的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性的复制到另外一块Survivor。当回收时,将Eden和Survivor中还存活着的对象一次性的复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间
当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion)。
标记整理算法
让所有存活对象都向一端移动,然后直接清理掉端边界以外的所有内存。
分代收集算法
根据内存的分代选择不同的垃圾回收算法。新生代(少量存活)用复制算法,老年代(对象存活率高)“标记-清理”算法
垃圾收集器
Serial收集器
最基本,发展最悠久
单线程垃圾收集器,整体性能低,对单线程单个性能高。
桌面应用
Parnew收集器
复制算法(新生代收集器)
多线程垃圾收集器, ,其中有一个与性能无关但很重要的原因是,除了Serial 收集器外,目前只有它能与CMS收集器配合工作。
Parllel Scavenge 收集器
复制算法(新生代收集器)
多线程垃圾收集器,
达到可控制的吞吐量
(吞吐量:CPU用于运行用户代码的时间与CPU消耗的总时间的比值)
-XX:MaxGCPauseMillis 垃圾收集器最大停顿时间
停顿时间短,用户交互好
-XX:GCTimeRatio 吞吐量大小,默认99,垃圾回收时间只占百分之一。
cms垃圾收集器Concurrent Mark Sweep
由于老年代
标记清除算法
工作过程:
1.初始状态,标记可被垃圾回收的对象,标记垃圾对象,通过引用计数法和可达性分析法,
2.并发标记,
3.重新标记,并发标记期间因用户程序继续运作而导致变动,相当于对并发标记的一个修正
4.并发清理
优点:并发收集,低停顿
缺点:占用大量的CPU资源,无法处理浮动垃圾,出现Concerrent Mode Failure,空间碎片。
G1收集器
优势:
并行和并发,利用多核cpu,并行缩短等待时间,并发提高速度
分代收集: 分成多个内存区域,通过Remember Set表进行 排序,选择回收区域效率最高的先回收。
空间整合:G1从整体来看是基于“标记——整理”算法实现的收集器,从局部(两个Region之间)上来看是基于“复制”算法实现的,但无论如何,这两种算法都意味着G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。
可预测的停顿:
使用G1收集器时,Java堆的内存布局就与其他收集器有很大差别,它将整个Java堆划分为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region(不需要连续)的集合。
在G1收集器中,Region之间的对象引用以及其他收集器中的新生代与老年代之间的对象引用,虚拟机都是使用Remembered Set来避免全堆扫描的。
G1中每个Region都有一个与之对应的Remembered Set,虚拟机发现程序在对Reference类型的数据进行写操作时,会产生一个Write Barrier暂时中断写操作,检查Reference引用的对象是否处于不同的Region之中(在分代的例子中就是检查是否老年代的对象引用了新生代中的对象),如果是,便通过CardTable把相关引用信息记录到被引用对象所属的Region的Remembered Set之中。
当进行内存回收时,在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会遗漏。
步骤:
1.初始标记
2.并发标记
3.最终标记
4.筛选回收
首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划
另外对筛选回收并发操作,可以减少停顿时间,降低吞吐量,可进行一些平衡。
标签:处理 eal 代码 扫描 root 相等 rri 回收 enc
原文地址:https://www.cnblogs.com/quyangyang/p/11005388.html