学习深入理解jvm虚拟机心得——谈谈GC垃圾收集器和回收策略(二)
1.前言
有幸有了大段完整的学习时间,本人也逐步调整心态静下心来看一看经典的java书籍。今天把gc章节看完,感觉脑子里比较混乱,可能是这一章节的新名词比较多吧,parallel scavange,parnew,serial啊等等。有必要将这些没记住的内容总结下来。我比较认同的一个观点就是,带着问题去学习。面试中问到的与jvm基础相关的肯定少不了gc。下面举例
a.堆内存中新生代老年代各自什么gc算法,为什么不同,还有什么算法。
b.创建大对象时,是在哪个分代中分配。
c.谈谈minor gc/major gc/full gc触发条件。
d.简述新生代老年代gc过程。
e.full gc是否真正回收了废弃对象。
以上问题摘自https://blog.****.net/fanx_000/article/details/80297487
2.如何判断对象是否存活
2.1 引用计数法,优点:实现简单,效率高。缺点:无法解决循环引用的问题。
2.2 可达性分析算法(这个名词有点绕),思路:通过GC Roots对象作为起点,开始向下搜索,走过的路径称为引用链。当一个对象和GC Roots之间没有引用链时,称这个对象是不可达的,即可回收的。
可作为GC Roots的对象包括:虚拟机栈中(栈帧中的本地变量表)引用的对象、本地方法栈(JNI)中引用的对象、方法区中的静态属性引用的变量、方法区中常量引用的对象。
2.3 引用的引申:java中创建对象时默认使用强引用,如Object a = new Object();除了强引用还有软引用、弱引用、虚引用。此概念不在这里扩展。
2.4 针对以上提出的问题e,我没有找到答案,是否是跟finalize()有关呢?
2.5 方法区回收
回收的对象为废弃的常量、废弃的类。回收的条件不在此多做介绍。注:大量使用反射、动态代理技术、cglib等bytecode框架,动态生成JSP等的场景都需要虚拟机具备类卸载的功能,以保证方法区不会溢出。
3.垃圾回收算法
3.1 标记-清除
该算法有两个过程,标记和清除。使用可达性分析算法标记哪些可回收的对象,然后统一对这些对象回收。
3.2 复制
该算法被设计成将内存分为大小相等的两块,每次只用其中的一块。当这一块的内存使用完了,就把还存活的对象复制到另外一块上,然后把当前内存一次清理掉。这样使得每次都是对整个半区进行清理,无需考虑内存碎片问题,只需移动堆顶指针,按顺序分配内存。
针对问题d-新生代的gc过程:新生代将内存区域分为一份Eden区和两个Survivor区,比例默认是8:1。每次使用eden区和其中一个survivor区。当回收时,将eden和survivor中仍存活的对象复制到另一个survivor区,最后清理掉eden和刚才用过的survivor区。(survivor空间不足会触发空间分配担保)
3.3 标记-整理
该算法分为两个阶段,标记过程与标记-清除算法相同,后续将仍然存活的对象向堆得一侧移动,最后对端边界以外的内存进行清理。
3.4 分代收集
针对问题a:新生代在gc回收时,存活的对象少,复制成本小,所以采用的是复制算法;老年代的对象存活几率大,并且没有额外的内存做分配担保,采用标记-整理算法。
4.Hotspot版本的算法实现
未完待续。。。