(JDK1.8)JVM GC整理——堆
一、判断对象是否消亡的算法
1、引用计数算法 —— 因为无法解决对象直接相互引用的问题,因此主流的java虚拟机没有选用此方法
基本思想:为每一个对象添加一个引用计数器,每当有一个地方引用这个对象时,计数器值加1,当引用失效时,计数器值减1;任何时刻计数器的值为0的对象都是可被回收对象。
2、可达性分析法
基本思想:将一系列被称为GC Roots的变量作为初始的存活对象集合,然后从该集合出发,所有能被该集合引用到的对象,将其加入到集合中,不能被该集合引用到的对象,则宣告它们死亡。
GC Roots : 是一些由堆外指向堆内的引用
一般而言GC Roots包括但不限于以下几种:
Java 方法栈桢中的局部变量;
已加载类的静态变量;
JNI handles;
已启动且未停止的 Java 线程
二、堆内存分布
1、新生代:
新生代按照8:1:1的比例分为Eden(伊甸区)和两个幸存区Survivor(from和to)
2、老年代
三、GC算法
1、标记清除:
标记清除是最早开发出来的算法。从根开始将可能被引用的对象用递归的方式进行标记,然后将没有被标记的对象作为垃圾进行回收
2、标记整理:
标记整理又称为标记压缩,是标记清除的变种。因为标记清除会造成很多内存碎片,标记整理就是将标记清除后的内存进行碎片整理
3、复制收集
将可用内存按容量划分为大小相等的两块区域,每次只使用其中一块,当这一块内存用完后,将该内存中所有存活的对象复制到另外一块内存上,然后把已使用过的内存一次性清理掉。
四、对象分配原则
1、新创建的对象优先分配到Eden区,如果Eden空间不足时,虚拟机执行一次Minor GC
2、大对象直接进入老年代——大对象是指需要大量连续内存空间的对象。这样做的目的是为了避免Eden区和两个Survivor区发生大量的内存拷贝
3、长期存活的对象进入老年代——虚拟机为每一个对象定义了一个年龄计数器,如果经历了一次Minor GC对象会进入Survivor区,之后每经历一次Minor GC,对象年龄加1,直到达到年龄阀值进入老年代
4、动态判断对象的年龄——如果Survivor区相同年龄的所有对象的内存大小总和大于Survivor内存空间的一半,则大于或等于该年龄的对象进入老年代
5、空间分配担保——每次进行Minor GC时,JVM会计算Survivor区进入老年代对象的内存大小,如果这个值大于老年代剩余内存空间大小,则进行一次Full GC;如果小于,则检查HandlePromotionFailure设置,如果true,则只进行Minor GC,如果false,则进行Full GC
五、GC策略
新生代可用策略
1、Serial Copying——串行GC
2、ParNew——并行GC
3、Parallel Scavenge——并行回收GC
老年代可用策略
1、Serial MSC——串行GC
2、Parallel MSC——并行GC
3、CMS——并发GC
G1收集器——引入分区的思路,弱化了分代的概念
GC策略+GC算法实现GC功能
六、GC流程
1、新创建的对象进入新生代Eden区,Eden区判断内存是否满了,如果满了,则执行Minor GC,将Eden区和Survivor from区存活的对象复制到 Survivor to区,清除Eden区和Survivor from区
2、在执行Minor GC后,Survivor to区中,对象年龄达到阀值对象移动到老年代,如果老年代剩余的内存空间小于Survivor to区移动过来的对象大小,则触发Full GC
3、如果触发Full GC后内存仍然不足,则抛出OutOfMemeryError异常