原文: https://www.jianshu.com/p/a62697f00b85
https://www.cnblogs.com/aspirant/p/8662690.html
https://www.cnblogs.com/yw-ah/p/5830458.html
判断对象是否存活的算法
- 1.引用计数算法
引用计数算法是垃圾回收的早期策略,堆中每一个对象都有一个引用计数,每有一个地方引用它,计数器就加一,当引用失效时,计数器减一
优点:执行快,适合程序不允许被长时间打端的场景
缺点: 如果两个对象互相循环引用,则检测不到
- 2.可达性算法
从一系列 “GC ROOT“ 节点开始,搜索引用的节点, 搜索过的路径称为引用链,当一个对象到GC ROOT没有引用链相连时,此对象就是不可用的(类似判断连通图?)
可作为GC ROOT的对象:
虚拟机栈中引用的对象 (栈帧中的本地变量)
方法区中常量引用的对象
本地方法栈中 JNI(Native方法)引用的对象
方法区中类静态属性引用的对象
PS:在可达性算法中,并不是一次判定后就决定是否回收
第一次筛选: 在可达性分析后与GC ROOT没有引用链相连时,标记为有必要执行 finalize()方法
第二次筛选: 在第一次被标记的对象中,如果在其 finalize()方法中 重新与引用链建立了联系,则从”即将回收“集合中移除。
- 方法区的垃圾回收
1. 废弃常量
废弃常量也是通过引用来判断,即没有任何地方引用的常量会被回收
2. 类
无用的类若要进行回收则需要满足以下三个条件:
(1) 该类所有的实例都已被回收, Java堆中不存在该类的实例
(2) 加载该类的ClassLoader 已被回收
(3)该类对应的java.lang.Class 对象没被任何地方引用, 即不会通过反射来访问该类
垃圾收集算法
- 1.复制算法
过程: 把可用内存按容量分为大小相等的两块,每次都只使用其中的一块,当这块内存用尽后,将存活的对象复制到另一块,然后将此块内存清空
优点:每次对整个半区进行操作,无需考虑内存碎片等复杂情况,实现简单,运行高效
缺点: 每次只能使用一半的内存,内存使用率降低
- 2.标记-清除算法
过程: 标记出需要回收的对象,然后统一清除所有被标记的对象
缺点: 产生的空间碎片太多,清除后有大量不连续的内存碎片,之后若要存储较大对象,因没有足够的连续内存则会触发另一次GC,影响系统性能
- 3.标记-整理算法
过程: 标记出需要回收的对象,然后进行整理,使存活的对象都向一端移动,最后直接清理掉边界以外的内存。
优点: 既没有像复制算法一样浪费50%的空间,也不像标记-清除算法产生内存碎片
(一般老年代会采用该算法)
- 分代收集算法
(1)新生代
新生代对象存活时间短,只有少量存活,适合使用 复制算法 复制少量存活的对象
新生代的内存按照8:1:1分为一个eden区和两个survivor区(后文简称S1,S2),对象大部分在eden区生成
在垃圾回收时,将eden区和S1区存活的对象复制到S2区,然后清空eden和S1,在第二次回收时,S1和S2的角色互换,即保证S1与S2始终一个为空,一个用于缓存 。
当S1或S2其中一个满了的时候,就将其中的对象转移到老年代。
或者survivor区未满,但其中的对象经历了一定次数的扫描仍然存活(默认为15次),虚拟机也会将它移动到老年代。
再或者如果是需要连续内存空间较大的对象,也会直接放入老年代,这样可以避免在survivor区反复复制大对象
新生代GC (Minor GC) 较为频繁,回收速度块
(2)老年代
对象存活率高,存活时间长, 适合使用 标记-清除 或 标记-整理算法,清理掉少数回收对象
年老代相对于新生代,内存更大,垃圾回收频率较低。
老年代GC (Major GC / Full GC) 频率低,速度比 Minor GC慢十倍以上
java的四种引用类型:
- 强引用(StrongReference)
- 具有强引用的对象不会被GC;
- 即便内存空间不足,JVM宁愿抛出
OutOfMemoryError
使程序异常终止,也不会随意回收具有强引用的对象。 - Object obj = new Object(); // 只有当obj 这个引用释放后,才会回收该对象
- 软引用(SoftReference)
- 只具有软引用的对象,会在内存空间不足的时候被GC,如果回收之后内存仍不足,才会抛出OOM异常;
- Object obj = new Object();
- SoftReference<Object> sf = new SoftReference<Object>(obj);
- 可以用 sf.get() 获取对象,当对象被标记为需要回收的对象时,返回null
- 软引用主要实现类似缓存功能,当内存足够时通过软引用取值,不从繁忙的真实来源查询数据,提升速度。
- 当内存不足时,自动删除这部分缓存数据,从真实来源查询数据。
- 弱引用(WeakReference)
- 只被弱引用关联的对象,无论当前内存是否足够都会被GC;
- 强度比软引用更弱,常用于描述非必需对象。
- Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
短时间内通过 wf.get()能获得对象,当执行过第二次垃圾回收后,将返回null - 用 wf.isEnQueued() 确认是否被垃圾回收器标记为即将回收
- 虚引用(PhantomReference)
- 仅持有虚引用的对象,在任何时候都可能被GC;
- 常用于跟踪对象被GC回收的活动;
- 必须和引用队列 (ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
- Object obj = new Object();
PhantomReference<Object> pf = new PhantomReference<Object>(obj);
pf.get();//永远返回null
pf.isEnQueued();//返回是否从内存中已经删除