哪些需要回收-》何时回收-》如何回收
一、哪些需要回收
1、引用计数算法(未采用)
缺点:很难解决对象之间循环引用的问题;
2、可达性算法
当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
GC Roots对象包括:
1>虚拟机栈(栈帧中本地变量表)中引用的对象
2>方法区中类静态属性引用的对象
3>方法区中常量引用的对象
4>本地方法栈中JNI引用的对象
3、引用
强引用:类似Object obj = new Object();
软引用:在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中进行第二次回收。
弱引用:被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
虚引用:对象被收集器回收时收到一个系统通知。
4、标记
如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那么它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为没有必要执行。
如果这个对象被判定有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,稍后由一个由虚拟机自动建立的低优先级的filalizer线程执行它。finalize()方法是对象逃脱死亡的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象重新与引用链上的任何一个对象建立管理,那么在第二次标记的时候它将会被移除即将回收集合;否则被回收。
任何一个对象的finalize()方法都只会被系统自动调用一次。
5、回收方法区
废弃常量
无用类:
该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例
加载该类的classloader已被回收
该类对应的class对象没有在任何地方被引用
二、什么时候回收
1、对象判活算法
枚举根节点(OopMap)->safepoint->safe region
三、如何回收
1、标记-清除算法
缺点:效率不高、空间问题(产生大量不连续的内存碎片)
2、复制算法(新生代)
将内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活的对象复制到另一块上面,然后将已使用过的内存空间一次性清理掉。
缺点:内存缩小为原来的一半。
Eden:survivor=8:1 每次使用eden和一块survivor
3、标记整理算法(老年代)
存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
4、分代收集算法
新生代、老年代选择合适的算法
5、垃圾收集器
Serial垃圾收集器
复制算法;client模式下的虚拟机是个不错的选择。
缺点:在进行垃圾收集时需要暂停其他所有的线程,直到他收集结束。
优点:简单高效。
ParNew收集器
Serial的多线程版本。复制算法;Service模式(后台程序时建议)下的虚拟机中新生代收集器的首选。
缺点:同serial一样。cpu多的时候比较不错。
优点:只有他能与cms收集器配合工作。
Parallel Scavenge收集器
复制算法;Paraller Scavenge收集器的目标是达到一个可控制的吞吐量(=运行用户代码时间/虚拟机运行时间);高吞吐量可以高效的利用CPU时间,尽快完成运算任务。适合在后台运算而不需要太多交互的场景。
GC停顿时间缩短是以牺牲吞吐量和新生代空间换来的:系统把新生代调小
优点:吞吐量优先
缺点:
Serial Old收集器
给client模式下的虚拟机使用。标记-整理
service模式下与Parallel Scavenge收集器配合使用,或者作为CMS收集器的预备方案。
Parallel Old收集器
配合Paraller Scaveng 标记-整理
CMS收集器
获取最短停顿时间为目标。标记-清除
只有CMS是标记-清除算法;
优点:并发收集、低停顿
缺点:1>CMS收集器对CPU资源敏感;默认启动线程数=(cpu数量+3)/4;当cpu较少是对用户影响很大。
2>CMS无法处理浮动垃圾;(出现在标记过后的垃圾)
3>基于标记-清除算法,产生大量碎片,提前出发Full GC
G1收集器
面向服务端的垃圾收集器;
将java堆划分成多个大小相等的独立区域(region),新生代和老年代不再物理隔离;建立可预测的停顿时间,是因为可以避免在整个堆中进行垃圾回收,G1跟踪各个region中的垃圾堆价值大小,在后台维护一个优先列表,每次根据允许的时间,优先回收价值最大的region;
优点:并行与并发、分代收集、空间整合、可预测的停顿;
四、内存分配与回收策略
1、对象优先在新生代Eden分配。当Eden没有足够空间进行分配时,虚拟机发起一次Minor GC;无法放入survivor,通过分配担保机制提前转移到老年代。
2、大对象(需要大量连续内存空间的对象)直接进入老年代
3、长期存活的对象进入老年代
如果对象在eden出生,并经过一个minor gc后仍然存活,并且能被survivor容纳的话,将被移动到survivor空间中,并且对象年龄设置为1。对象在survivor中每熬过一个moinor gc年龄加1,当他年龄到达一定程度(默认15次),就会晋升到老年代。
动态对象年龄判断:如果在survivor空间中相同年龄所有对象的大小总和大于survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代;
空间分配担保:在发生minor GC之前,虚拟机先检查老年代最大可用连续空间是否大于新生代所有对象的总空间,如果成立,Minor GC可以确保安全。如果不 成立,虚拟机查看HandlePromotionFailure设置值是否允许担保失败。如果允许,检查老年代最大可用连续空间是否大于历次晋升到老年代对象 的平均大小,如果大于,尝试一个minor GC,如果小于,或者不允许冒险,这时进行一次full GC.
查看使用的垃圾收集器:java -XX:+PrintCommandLineFlags -version