【JVM】垃圾回收算法总结

垃圾回收算法有不少种,目前商业虚拟机经常使用的是分代回收算法,但最初并非用这个算法的
咱们来看一下垃圾收集算法的背景知识算法

标记-清除算法
最基础的垃圾回收算法,顾名思义,整个回收过程分两步:
1.逐个标记
2.统一回收
该算法能够算是后来全部垃圾回收算法的基石(后续全部算法都有标记和清除这两步,只不过策略上有了一些优化)
这里值得一说的是这个标记 虚拟机是如何判断一个对象是“活”仍是“死”?
所以又引出两种标记算法:
1.引用计数算法
引用计数算法很是简单且高效,当一个对象被引用一次则+1再也不被引用则-1,当计数为0就是不可能在被使用的对象了,可是这种算法存在一个致命的缺陷:两个对象相互引用对方呢?因此,这种算法确定不能用,pass掉
2.可达性分析算法
目前的标记算法主流实现都是用的可达性分析算法。就是以一个叫GC Roots的对象为起点,经过引用链向下搜索,若是一个对象经过引用链没法与GC Roots对象连接,就视为可回收对象,上面说的那种相互引用的状况天然也解决了。
扩展:即便是可达性分析中不可达的对象也并非非死不可,只是暂处‘缓刑’,真正宣告一个对象死亡至少还要经历两次标记过程:当被断定不可达以后那么他被第一次标记并进行筛选,若对象没有覆盖finalize()方法或者finalize()方法已经被虚拟机调用过就‘放生’,若是被断定须要执行finalize()方法就会被放到一个叫F-Queue的队列中进行第二次标记对象被再次被引用就会放生,不然就会被回收。
finalize()方法
finalize()是Object中的方法,当垃圾回收器将要回收对象所占内存以前被调用,即当一个对象被虚拟机宣告死亡时会先调用它finalize()方法,让此对象处理它生前的最后事情(这个对象能够趁这个时机挣脱死亡的命运)性能

说到这里敏锐的小伙伴可能以及察觉到了,上面都在说引用因此引用的定义就显得尤其关键了
JDK1.2后Java对引用的概念进行了扩充,将引用分为:强引用、软引用、弱引用、虚引用四种测试

强引用:用处很大,不管如何都不会被GC回收
软引用:有必定用处但不大,内存实在不够才会在内存溢出以前回收掉
弱引用:比软引用强度更弱一些,GC会让它多活一轮,下一轮就回收
虚引用:必回收,惟一做用就是被GC回收时会收到一个系统通知

复制算法
前面说的标记-清除算法其实两个过程效率都很低,而且回收以后内存被‘抠出不少洞’内存碎片化严重,此时若是过来了一个较大的对象,找不到一整块连续的内存空间就不得不提早触发另一次GC回收。
而复制算法则选择将内存一分为二每次只使用其中一半,满了以后将存活的对象整齐复制到另外一块干净的内存上,将剩下的碎片一次性擦除,简单高效。可是也存在一个很大的缺陷,那就是可用内存变为原来的一半了。优化

分代收集算法
事实上后来IBM公司通过研究发现,98%的对象都是‘朝生夕死’,因此并不须要1:1的划份内存,即咱们如今经常使用的分代收集算法:
根据对象的存活周期将内存划分为两块,分别为新生代和老年代,而后对各代采用不一样的回收算法,在新生代中大部分是‘朝生夕死’的对象,继续将新生代8:2划分为Eden区和survival区,其中survival区1:1分红s0和s1两块,采用以前说的复制算法,减小内存碎片的产生。
新生代满了会进行一次minor GC ,minor GC 存活的对象转移到survival区,survival区满了就会将survival区进行回收,存活的survival区对象复制到另一块survival区中,而且survival区对象每存活一轮年龄+1当到达必定年龄就会前往老年代。日志

扩展01:JVM什么时候会进行全局GCcode

01.手动调用System.GC 但也不是当即调用
02.老年代空间不足
03.永生代空间不足
04.计算得知新生代前往老年代平均值大于老年代剩余空间

扩展02:在压力测试时,发现FullGC频率很高,如何解决对象

01.观察GC日志,判断是否有内存泄漏,或者存在内部不合理点
02.调整JVM参数,如新生代、老年代大小 S0+S1大小比例,选用不一样的当即回收器
03.Dump内存,作进一步的对象分析
04.压测脚本的编写,性能问题解决前能够发现问题,并对解决方案进行验证
相关文章
相关标签/搜索