搭理算法的核心:分代回收算法
算法的作用域:新生代、养老带、永久代
新生代频繁,养老区次数少。(永久代不会产生垃圾)
普通GC | Full GC | |
---|---|---|
产生条件 | 伊甸园区满 | 养老代满 |
请理结果 | 存活的对象进入幸存区 | 进行一定数量的清理(默认15), 仍存活进入养老区 |
清理范围 | 新生代(伊甸园区和2个幸存区) | 整个堆(主要是新生代养老代) |
算法:
引用计数法
查看对象目前引用的情况,来判断是不是该被清理。
每个对象都有一个目前引用的情况,监控会清理引用次数为0的对象。当对象被引用就增加1,如果不用了就减1.
缺点:
有些对象初始化很消耗内存,但引用次数不多,不应该被清理。
内部对象形成了相互引用,即便不再使用引用次数也不会成为0。
计数器维护麻烦
jvm一般不用
复制算法
年轻代中用的就是复制算法。
首先对象会产生在伊甸园区,当伊甸园区满了以后进行一个GC。淘汰了基本上99%对象。
清理一次数据进入from区此时伊甸园区基础产生对象。知道有一次出发GC ,进行垃圾回收。
这一次的GC,伊甸园区的数据到to区,同时from区的数据也进入to区。to区和form区换一下名称。即从结果看来:伊甸园 —> to 、from —>to,而to永远是那个空的区。
经过一次GC不仅是减少了伊甸园区的数据,同时也减少了幸存区(s0、s1)的数据。复制算法的本质就是不断地把剩下的数据放到那个空的区域,同时将腾出来的区域改成to。如果from区和伊甸园区都满了,则会触发一次fullGC。
使用场景:空间不大经常产生新数据的区域
优点:没有标记和清除的过程!效率高!没有内存碎片!
缺点:需要浪费双倍的空间
统计:99% 对象都会在使用一次之后,引用失效!
标记清除
老年代一般使用这个,但是会和我们后面的整理压缩一起使用!
两步:标记+清除
优点:不需要额外的空间!
缺点:两次扫描,耗时较为严重,会产生内存碎片,不连续!
标记清除压缩!
对上一步的内存空间进行清除,即压缩无用的空间。
弥补了标记清除算法的不足,但是多了移动数据,会更加降低效率。用时间换空间
使用场景:不经常清理的区域。可以有时间进行数据移动的区域。
小总结
内存效率:复制算法 > 标记清除算法 > 标记整理(时间复杂度!)
内存整齐度:复制算法=标记整理>标记清除算法
内存利用率:标记整理 = 标记清除算法 > 复制算法
从效率来说,复制算法最好,但是空间浪费较多!为了兼顾所有指标,标记整理会平滑一点,但是效率不尽人意!
没有通用的算法,要根据不同的使用环境选择最适合的算法-----用分代收集算法即不同的代用不同的算法。