垃圾回收与算法(一)
垃圾判定算法
1、引用计数法
通过对象被引用的数量判断对象是否为垃圾对象,若该对象被引用数为0,则该对象被标记为垃圾对象,等待垃圾回收器清除。
缺陷:
A.object = B;
B.object = A;
A与B两个对象互相引用,除此之外再无别的对象引用这两个对象,此时A与B均为垃圾对象,但是引用计数法无法判断.
2、可达性分析
目的: 为了解决引用计数法的无限循环问题.
从GC ROOT开始,遍历引用链,对于引用链无法到达的对象,标记为垃圾对象(期间,对象可以通过自救逃脱被回收的命运),等待垃圾回收器回收。
GC ROOT
1、方法区中的静态引用
2、方法区中的常量
3、虚拟机栈中的对象
4、本地方法栈中的对象
跨代引用
现在的虚拟机中基本上都有老年代和年轻代之分,而跨代引用则是指老年代与年轻代之间的相互引用。
强分代假说:越老的对象越难死亡
弱分代假说:大多数对象在年轻的时候死亡
分代回收基础理念:
将对象依据“年龄”分配到不同的区域,每次回收之回收其中的一个区域。即Major GC和Minor GC
缺陷:
对于年轻代中的对象,其可能被老年代所引用,而当跨代寻找引用时,就相当于要遍历老年代,存在性能浪费;
解决方案:
采用引用记忆集的方式存储夸代引用,避免全年龄段遍历。
缺陷:记忆集存在滞后性,无法及时更新
对象的自救
不可达对象->标记一次->判定是否有必要执行finalize()方法:
1、执行,放入F-QUEUE队列,稍后有虚拟机自动建立的、低优先级的Finalizer线程执行,建立引用关系,自救成功。
2、不执行,放弃治疗,垃圾回收
方法区(永久代)回收
1、废弃常量回收:
无引用该常量的对象
2、无用类回收:
1、该类的所有实例均已被回收
2、加载该类的ClassLoader已经被回收
3、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
垃圾回收算法
1、标记清除算法
标记
遍历整个Java堆,标记需要清除的对象
清除
回收被标记对象所占用的空间
缺陷
内存碎片化严重
2、复制算法
将内存分为两块,一次使用其中一块,垃圾回收时,将存活对象复制到未使用的内存上,将当前使用内存整块清除。
缺陷:
空间利用率低,且对于大量对象的复制消耗大
3、标记整理清除算法
4、分代收集算法
分为老年代和年轻代
年轻代
存活率低,回收对象多
复制算法(8:1:1)
1、Eden区:对象初创时,会存储在此区,对于一些较大的对象会被直接放入老年代,垃圾回收后,Eden区会被清空
2、to survivor区:进行垃圾回收时,会将from区和Eden区的存活对象移入此区,对于一些,存活次数超过JVM的存活阈值的对象,将会被移入老年代,to区转变成from区
3、from survivor区:存活对象被移除后,from区被清除,转变为to区
老年代
存活率大,回收对象少
标记复制或者标记整理算法
被移除后,from区被清除,转变为to区
老年代
存活率大,回收对象少
标记复制或者标记整理算法