标签:分代 不能 回收 hold 情况 建议 ace 遍历 查看类
一.如何判断对象已经死亡
1.引用计数 无法处理循环引用的情况
2.可达性分析 目前主流实现方式。
原理: 从GC Roots对象作为起点开始查询,如果有引用链说明对象存活,反之就是已经死亡。
GC Roots对象:
(1)栈(栈帧)中引用的对象。
(2) 方法区中类静态变量引用的对象。
(3)方法区中常量引用的对象。(final 修饰的属性)
(4) 本地方法栈中引用的对象。
引用类型:
(1) 强引用: new创建的,该类引用GC不能回收。
(2) 软引用: 有用非必须,可回收也快不回收,一般用在缓存中。只有在内存紧张的时候才回收。
(3)弱引用: GC会回收,所有生存周期是一个GC
(4) 虚引用: 可以忽略的引用,对对象没有任何影响。
可达性分析过程:
两次标记:
(1)第一次检查不可达后,如果该对象覆盖了finalize()方法,切没有被调用过,就把对象放到 F-Queue队列中,虚拟机的Finalizer线程会去依次调用改队列中的所有对象的finalize()方法(只调用不等待返回,以免影响系统)。
(2)GC对 F-Queue队列进行二次标记,如果在finalize()被其他对象引用了,就移出队列。否则,才会被回收。
备注:每个对象的finalize()只会被调用一次。所以上面2中的情况只能进行一次。官方不建议使用这种方式复活对象。
二 垃圾回收
1.方法区回收
回收内容:
(1)废弃常量 string对象
(2)无用的类:判断条件 a.类的对象都被回收 b.加载类的ClassLoader已经被回收 c. 该类的java.lang.Class对象没有任何地方引用,也不能通过反射来创建。
参数:
-verbose:class
-XX:+TraceClassLoading:查看类加载信息
-XX:+TraceClassUnLoading:查看类卸载信息
2.回收算法
(1)标记清除(Mark-Sweep)
会产生内存碎片,且效率不高。适合存活比例比较高的区域
(2)分代复制
效率高,内存存在浪费。不会产生碎片。适合存活比例低的区域,比如新生代,90%的对象都会被回收,只把存活的复制到其他地方,统一清除原来的区域。
(3)标记整理
在标记清除的基础上增加整理功能,消除内存碎片。
三 HotSpot算法实现
1.使用可达性分析来判断对象是否已死。
2.为了尽量减少系统停顿(stop the world)设置安全点(系统特定的状态,这个状态下GC不会引起问题)和安全区
原理:GC在需要中断线程的时候设置一个标志,每个线程都去遍历这个标志,如果标志是需要中断,就挂起自己。
3.垃圾收集器:
年轻代:Serial ,ParNew , Parallel Scavenge
老年代:CMS, Serial Old , Parallel Old
G1:既可以在年轻代也可以在老年代。
Serial:
单线程收集器 stop the world 造成系统停顿,体验很差
参数:
-XX:SurvivorRatio :设置 Eden和Survivor的比例 默认是8
-XX:PretenureSizeThreshold : 新对象大于这个值直接放入老年代。
-XX:MaxTenuringThreshold: 年龄最大值,大于这个就会复制到老年代。
Serial old
单线程,标记整理算法
ParNew
Serial的多线程版本,其他跟Serial都一样
ParNew old
多线程,标记整理。
CMS收集器
1.5推出的目前应用最广的一个收集器,获取最短停顿时间。
步骤
(1)初始标记
stop the world 只记录GC Roots直接关联的对象。
(2)并发标记
跟用户线程并发执行,进行可达性分析,也就是GC Roots Tracing过程。
(3)重新标记
stop the world 由于上面是并发执行,在这个过程中有可能产生新的垃圾对象,所有需要重新标记。
(4)并发清除
跟用户线程并发执行
分析:(2)(4)是耗时最长的,现在可以并发执行从而减少系统停顿。
缺点:
(1)并发清除过程中的垃圾无法回收,只能等下一次
(2)基于标记清除实现的,会产生内存碎片,CMS也支持整理,但是,整理过程没法并发,会加大停顿时间。
G1收集器
目前没有大规模商用。唯一一个即支持新生代又支持老年代的收集器。
基本思路:
把内存划分区域,不再是物理区分新生代和老年代,每个区域计算回收价值(回收大小和回收时间的比值)。优先回收价值高的。回收过程跟CMS类似,只是是以region为单位的。
GC日志如何查看:
对象年龄问题:
每复制一次age就加一,超过设定值就会移动到老年代。
年龄动态判定:Survivor空间中年龄相同的对象总行大于空间一半,就把比这些大的对象移动到老年代。
名词解释:
Minor GC: 回收新生代
Full GC:新生代和老年代都进行回收。
回收过程:
1.最初eden和survivor都是空的,新创建的对象放到eden中,当eden满了后会触发minor GC,把存活的对象放到s1中,并清理掉不被使用的对象。这个时候Eden是空的和s1中包含存活的对象。
2. 当慢慢的eden又被填满后,会再次触发minor GC,这个时候会把eden中存活的对象放到s2中,同时s1中存活的也会复制到s2中,然后清理垃圾对象。
3.上面2中的步骤会不断反复。
4.对象在第一次被复制的时候会设置age=1,以后没复制一次就加1,当上面的步骤不断的累加使得age大于设定的值-XX:MaxTenuringThreshold的时候,就会转入到老年代。转入老年代的方法不止这种情况,另外还有两种,
(1)每次minor GC的时候如果被复制对象大于要放到的s空间,就会放入老年代。
(2)新对象创建的时候如果大于设定值-XX:PretenureSizeThreshold会直接放入老年代,此参数只对Serial及ParNew两款收集器有效
(3)Survivor空间中年龄相同的对象总行大于空间一半,就把比这些大的对象移动到老年代。
所以老年代是存放较大对象和存活时间足够长的对象。
5.老年代满了的时候回触发 full gc,使用的是标记-清除方式,JVM先扫描一遍,把要删除的对象做上标记,然后阻塞所有用户进程进行清除,并且把存活对象集中一下,避免造成过多内存碎片。
标签:分代 不能 回收 hold 情况 建议 ace 遍历 查看类
原文地址:https://www.cnblogs.com/fymc/p/11073992.html