垃圾回收算法:
引用计数法:
对象头部维护一个count计算引用次数,当为0的时候判断可以作为垃圾清除;
问题:无法区分引用类型,无法解决循环引用(会死锁永远无法garbage collection)
可达性分析算法:
通过gc root向下遍历整个对象引用图,这些对应都是存活对象,那么剩下来的就是无法和gc root建立引用链的都是无用对象(因此就算存在相互引用,这两个引用的对应都是无法到gc root存在引用链的,因此都是垃圾对象);也就是说可达性分析和引用计数出发点不同,前者判断存活,剩下的全是要筛选的垃圾,前者相反;
// 什么可以作为gc root
因此JVM的垃圾回收采用可达性分析算法判断对象是否是垃圾
垃圾回收具体实现:
标记清除算法:给需要回收的地方加上标记然后清除,效率高,但是会有大量内存碎片;
复制算法:专门解决内存碎片问题,将内存一分为二,左边回收将非垃圾复制到右边然后集体回收;不会产生内存碎片;但是内存变小,因为始终只有一半内存可用,一半为空。
标记整理算法:将需要清除的先标记,然后将垃圾内容统一移到最左边或最右边然后集中清理;不会产生内存碎片,但是大量修改对象内存引用地址,效率比复制算法低很多;
整合三种算法之长:分代收集算法,也就是JVM采用的回收垃圾算法
年轻代占比:
1/3 (其中Eden(死亡伊甸园 百分之98的对象会在这里GG)占比 8/10 Survivor区中两块: from占比 1/10 to占比 1/10)
老年代占比:
2/3 (垃圾回收算法采用标记整理算法)
年轻代回收:(Minor GC)
存活区(Survivor的from和to):每次来自Eden和from的存活采用复制算法保存到to区然后整体清除回收Eden和from区;
采用复制算法原因:避免内存碎片因此排除标记清除,考虑效率和存活的对象比较少,使用复制算法;
老年代回收:(Major GC)
采用标记整理算法;过程采用Stop The World,内存越大,STW时间越长;
原因:老年代的内存较大,如果要用复制算法只能使用一半过于浪费,而且过多的复制效率较低,又要避免大量内存碎片,因此使用标记整理算法;
为什么要有Survivor区?
相当于Eden区和老年代的缓冲区,因为并不是进入Survivor区的就能成为老年代的对象,很有可能在接下来的垃圾回收里回收掉,大多数情况下在Survivor存活15次及以上才能进入老年代;因此Survivor区的目的是为了减少老年代GC的压力;
对象进入老年代的情况?
to区满了,那就全部进老年代;在Survivor区存活时间超过15次可以直接进入老年代;survivor区相同年龄对象大小总和超过survivor区的一半则一起进入老年代(称作动态年龄对象);连续内存空间的大对象直接进入老年代,无论是否是“朝生夕死”对象,目的是为了避免survivor俩区之间的大量复制;(如果系统存在大量这样的对象,就会多次触发Major GC,需要注意)