GC相关
1.对象被判定为垃圾的标准?没有被其他任何一个对象引用
-
引用计数算法
- 阐述
判断对象的引用数量来决定对象是否可以被回收
每个对象实例都有一个引用计数器,被引用则+1,完成引用-1
任何引用计数为0的对象实例可以被当作垃圾来收集 - 优点:执行效率高,程序执行受影响较小
- 缺点:无法检测出循环引用的情况,导致内存泄漏
- 阐述
-
可达性分析算法
- 通过判断对象的引用链是否可达来决定对象是否可以被回收
在Java中,是通过可达性分析(Reachability Analysis)来判定对象是否存活的。该算法的基本思路就是通过一些被称为引用链(GC Roots)的对象作为起点,从这些节点开始向下搜索,搜索走过的路径被称为(Reference Chain),当一个对象到GC Roots没有任何引用链相连时(即从GC Roots节点到该节点不可达),则证明该对象是不可用的。
- 通过判断对象的引用链是否可达来决定对象是否可以被回收
-
在Java语言中,可作为 GC Roots 的对象包括下面几种:
虚拟机栈(栈帧中的局部变量表)中引用的对象。(即Java方法中局部变量引用的对象)
方法区中类静态属性引用的对象。(即类的静态变量引用的对象)
方法区中常量引用的对象。(即类的常量引用的对象)
本地方法栈中 JNI 引用的对象。(即 Native 方法中局部变量引用的对象)
1.标记-清除算法
- 标记:从根节点进行扫描,对存活的对象进行标记
- 清除:对堆内存进行线性遍历,回收不可达对象内存,然后将所有标记全部清除,方便下一次的标记
优点:实现简单
缺点:由于标记清除不需要对象的移动,只对不存活的对象进行处理。标记清除后,可能会产生
大量的碎片,当下一次需要创建较大内存的对象时,不得不触发下一次垃圾清除操作,使对象成功创建。
2.复制算法
分为对象面和空闲面
对象在对象面上创建
存活的对象被从对象面复制到空闲面
将对象面所有对象内存清除
在内存分配时,分为对象面和空闲面。对象面上保存新创建的对象,当触发垃圾回收后,对象面上存活的对象会拷贝到空闲面上,然后清除对象面。
优点:1.顺序化分配内存,实现简单,运行高效
2.解决碎片化问题
3.适用于对象存活率低的场景
缺点:需要空闲面的保证,浪费空间。如果此时有一次垃圾回收,对象面有大量的对象存活。那么copy到空闲面上就要占据大量的内存。所以只适用于那些“朝升夕死”的线程。即存活时间短的对象。
3.标记-整理算法
在标记清除的基础上进行对象的移动,成本更高!
优点:
1.不用设置两块内存互换
2.避免内存的不连续性
3.适用于存活率高的场景
缺点:在标记清除算法的基础上,增加了对象按地址进行排序的操作。效率低一些
4.分代手机算法(组合拳)
-
垃圾回收算法的组合拳
-
按照对象声明周期的不同划分区域以采用不同的垃圾回收算法
jdk 8 后 保留了年轻代,老年代
堆内存划分的比例 -
年轻代:分为Eden区,两个Surivivor区(from,to)。
年轻代存活率低,采用复制算法。老年代存活率高,采用标记-整理算法 -
Gc的分类
Minor Gc(年轻代垃圾回收)- 一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,
如果仍然存活,将会被移到Survivor区。对象在Survivor区中每熬过一次Minor GC,年龄就会增加1岁,
当它的年龄增加到一定程度时,就会被移动到年老代中。
Full Gc(老年代垃圾回收)
1.存放声明周期较长的对象
2.通过标记-整理算法进行回收
当触发Full Gc时,通常伴随着对年轻代的堆内存也进行回收! - 触发Full Gc的条件
1.老年代空间不足
2.永久代空间不足:(永久代:永久代主要存在类定义,字节码,和常量等很少会变更的信 息。并且永久代不会发生垃圾回收,如果永久代满了或者超过了临界值,会触发完全垃圾回收 (Full Gc))而jdk1.8后把堆中永久代存放的数据移动到了元空间中,降低Full Gc的频率
3.promotion failed :在进行Minor GC时,survive区放不下了,对象只能放在老年代中。此时老年代也放不下。此时会触发Full Gc
4.concurrent mode failure:在执行Full Gc的时候。有对象要放到老年代中,而此时老年代空间不足。
5.Minor GC晋升到老年代的平均大小大于老年代的剩余空间
6.调用System.gc()
- 一般情况下,新创建的对象都会被分配到Eden区(一些大对象特殊处理),这些对象经过第一次Minor GC后,
-
对象如何晋升到老年代?
- 经历一定Minor次数依然存活的对象
- Eden区或Survivor区中存放不下的对象
- 新生成的大对象