Java的GC,垃圾回收机制。
目前常用的标记算法有两种,主要是为了对垃圾进行标记,为之后进行垃圾回收做准备:
1:引用计算算法;
2:可达性分析算法;
目前常用的垃圾回收算法有三种:
1:标记-清除算法;
2:标记-整理算法;
3:复制算法;
目前使用的GC:【jdk1.8版本已经没有永久代了】
1:MinorGC方式(主要用于年轻代,具体点的是Eden区满时触发GC。)
2: FullGC方式(收集整个Java堆和方法区的垃圾收集。)
3: Major GC (针对 老年代的垃圾收集。 目前,只有CMS收集器会有单独收集老年代的行为)
4: Mixed GC (收集整个新生代以及部分老年代的垃圾收集。 目前只有G1收集器会有这种行为。)
模型概述,将堆内存分为年轻代和老年代,年轻代占1/3,老年代占2/3 ;
其中年轻代一个Eden区,两个Survivor区 【Eden :S : S 为 8:1:1 ;】
java在进行内存回收的时候需要判断当前对象是否为垃圾,才能进行回收。
对象被判定为垃圾的标准:没有被其他对象引用;
判定对象是否为垃圾的算法:引用计数算法;可达性分析算法;
1:引用计算算法:通过对象实例的引用计数器是否为0来决定对象实例能否被当做垃圾收集,被引用+1,完成引用-1,0收集。
优点:执行效率高,程序执行受影响较小;
缺点:无法检测出循环引用的情况,导致内存泄漏;
2:可达性分析算法:判断对象的引用链是否可达来决定对象是否可以被回收
具体:从GCRoot出发,对内存中的整个内存图进行遍历,不断标记存活对象,最后将不可达的回收
标记-清除算法:先标记(可达性算法),在清除,会产生大量不连续内存碎片。
标记-整理算法:先标记(可达性算法),在清除,再整理,避免碎片内存产生,使用于存活率搞的场景(老年代)
复制算法:当对象面空间不够时,会将对象面存活对象复制到空闲面,并将对象面所有对象内存清除。解决产生碎片内存问题,顺序分配内存,简单高效,适用于对象存活率低的场景(适用年轻代,据统计每次回收只有10%对象存活)
分代收集算法:按对象声明周期不同划分区域并才采用不同算法,提高jvm回收效率。年轻代存活率低使用复制算法,老年代对象存活率高使用标记-清楚/标记-整理算法。
GC分类:MinorGC方式(主要用于年轻代)、FullGC方式(主要用于老年代)
年轻代:尽可能快速收集掉生命周期短的对象,Eden区,两个Survivor区(from区to区),一次MinorGC,活着对象年龄加1,默认15岁进入老年代(--XX:MaxTenuringThreshold 设置新生代最大年龄)
年轻代垃圾回收过程概述:
1:每次年轻代的Eden区满了之后,会进行一次MinorGC,清理Eden区,此时将Eden存活对象【 假设存在对象A 】复制到from区,之后Eden清空,此时存活对象年龄为1。如图:
初始Eden区域满了,A的年龄为0
进行一次MinorGC,A的年龄为1
2: Eden再次满了之后,再次进行一次MinorGC,将Eden存活的对象【 假设存在对象B 】复制到to区。同时将form区的对象A 复制到 to 区,并将Eden、from区清空。此时对象A的年龄为2,对象B的年龄为1。如图:
进行一次MinorGC,A的年龄为2,B的年龄为1
3:Eden再次满了之后,再次进行一次MinorGC,将Eden存活的对象 以及 to 区的存活对象复制到from区,将Eden、to区清空。此时对象A的年龄为3,对象B的年龄为2。如图:
进行一次MinorGC,A的年龄为3,B的年龄为2
注意,默认超过15岁进入老年代。进入了Survivor区的对象失效也会被清除。
老年代:存放生命周期较长的对象; FullGC比MinorGC慢,但执行频率低。
触发FullGC条件:
老年代空间不足;
永久代空间不足(jdk7及以前版本);
CMS GC出现fail;
MinorGC晋升到老年代的平均大小大于老年代的剩余空间;
调用System.gc();
使用RMI进行RPC或管理的jdk应用,每小时会执行1此FullGC