天天看点

java:垃圾~判定&&回收,Stop the World~~!

垃圾回收算法:

引用计数法:

        对象头部维护一个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,需要注意)