架构训练营第九周作业
请简述 JVM 垃圾回收原理。
1.JVM对象是否可以被回收——对象的可达性算法。
JVM对象的引用关系如果不能够到达GC Root(如果在对象和GC Root之前不存在可达路径),代表对象可被回收。
在Java语言中,可作为GC Roots的对象包含以下几种:
虚拟机栈(栈帧中的本地变量表)中引用的对象。(可以理解为:引用栈帧中的本地变量表的所有对象)
方法区中静态属性引用的对象(可以理解为:引用方法区该静态属性的所有对象)
方法区中常量引用的对象(可以理解为:引用方法区中常量的所有对象)
本地方法栈中(Native方法)引用的对象(可以理解为:引用Native方法的所有对象)
(上面4种GC Roots对象摘抄网上资料,自己理解:1为栈中的变量,大部分new出来的对象的引用变量都在栈中,为GC Root;static引用变量,生命周期在class被卸载时结束,生命周期长;final对象,也在方法区中,生命周期长;native引用对象,不常见)。
2.分代算法
JVM根据内存对象的生命周期,分为年轻代和老年代以及永久代。
年轻代“复制整理”算法:
分为三个区,eden、from、to,发生minor gc时eden+from的对象会清理,如果仍然不能回收的对象根据经历的gc次数决定是否晋升到老年代还是到to区。算法为什么不使用两块区域相互拷贝清理,因为这样的话内存的有效使用率只能达到50%,并没有充分利用好在年轻代大部分对象都可以回收的特性。所以只需要保留很小的一部分区域(to区),保障每次minor gc后能够存储下依然活着的对象即可。这样整个内存的使用率就能到(eden+from)/(eden+from+to)。
年轻代的gc算法保障了每次新对象的申请能够申请完整的一块大内存,不像老年代的回收算法,内存回收后不连续。
为什么说young gc能够不“stop the world”呢?如果在执行内存清理拷贝的过程中,来了一个新对象,如何处理呢?查了资料,在发生young gc时标记哪些对象存活的时候依然需要STW,只不过是young gc的停顿时间很短(大部分对象可回收,而老年代很多对象大部分都是alive),我们常常关注full gc的时长。
根据标记和拷贝过程中是否多线程执行,具体的实践算法有串行和并行(ParNew)之分
老年代的“并发标记-清除”算法(CMS)
老年代的算法思想是“标记-清除”,至于并发标记,也是为了减少STW的时间,达到快速响应的目的(减少响应时间)。具体算法执行阶段:
“初始标记”(STW)——并发标记——并发预清理——并发重标记(STW)——并发清除
评论 (1 条评论)