JVM垃圾收集
Posted yangyh01
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM垃圾收集相关的知识,希望对你有一定的参考价值。
判断对象是否存活的方法:
1、引用计数算法:给一个对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加1,引用失效时,计数器减1,当引用数量为0时,任务对象已经死了
缺点:当对象之间存在相互循环引用时,引用计数算法无法通知GC收集器回收
2、可达性分析算法:判断一个对象到GC ROOTS是否有任何引用链相连,当一个对象到GC ROOTS没有任何引用链相连时,证明此对象是可回收的
在java语言中,可作为GC roots的对象包括下面几种:
虚拟机栈中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(native方法)引用的对象
引用分类:强引用,软引用,弱引用,虚引用
回收方法区:
很多人认为方法区是没有垃圾收集的,在方法区中进行垃圾收集的性价比比较低,在堆中,新生代的进行一次垃圾收集一般可以回收70%到95%,而永久代中的垃圾收集效率远远低于堆,
但是当大量使用反射,动态代理等这类频繁自定义classloader的场景都需要虚拟机具备类卸载的功能,以保证永久代不会溢出
垃圾收集算法:
标记-清除法:标记完后,统一回收所有被标记的对象,主要不足是:一个是效率问题,标记和清除两个过程的效率都不高,另一个是空间的问题,标记清除后会产生大量不连续的内存碎片,空间碎片太多,可能会导致后续需要分配大内存对象时,无法找到足够连续的内存空间而触发另外一次垃圾收集动作
复制算法:将内存划分为两块大小相等的区域,当其中一块用完时,将还存活的对象复制到另外一块上面,然后再把使用过的内存空间一次清理掉,每次都是对整个半区进行内存回收,内存分配时不用考虑内存碎片等复杂情况
目前虚拟机都采用这种收集算法来回收新生代,将内存划分为一个较大的eden空间和两个较小的survivor空间,每次只是用一个eden区间和一个survivor空间,默认大小比例为8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%,只有10%会浪费,另外没有办法保证每次回收都只有不多余10%的对象存活,当survivor空间不够用时,需要依赖其他内存进行分配担保
标记-整理算法:
复制收集算法在存活率比较高时,会进行较多的复制操作,效率会变低,关键时如果不想浪费50%的空间,就需要有额外的空间进行分配担保,标记-整理算法,后续步骤不是直接对可回收的对象进行清理,而是让所有存活的对象都像一端移动,然后直接清理掉端边界以外的内存
分代收集算法:就是根据对象存活周期的不同将内存划分为几块,一般是把java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最合适的收集算法
以上是关于JVM垃圾收集的主要内容,如果未能解决你的问题,请参考以下文章