JVM面试总结(2)-垃圾回收器与内存分配策略
1.判断对象回收条件:
1,引用计数算法:添加一个计数器来记录。有一个引用就+1.引用失效就-1.任何时候为0就死了。但是不能解决相互循环引用的问题。
2.可达性分析算法(主流):选择一个对象作为起点。一个对象到GC roots链不可达就是不可用。
起点的选择:
1.虚拟机栈(栈帧中的局部变量表)中引用的对象
2.本地方法栈中JNI(native)中引用的对象
3.方法区中常量引用的对象
4.方法区中静态属性引用的对象
方法区的回收只要是废弃常量(没有引用指向该常量)和无用的类的回收。
无用类的判断条件:
-
该类的所有实例被回收了。在堆没有该类的实例
-
加载该类的ClassLoader已经被回收了
-
该类对应的class对象没有任何地方被引用,不能通过反射访问该类。
四种引用类型: -
强引用:普遍存在的。new出来的都是。强引用还存在就不会回收。
-
软引用:有用但非必需,在将将要发生内存溢出的时候,会回收。使用SoftReference来实现软引用。
-
弱引用:指向非必需的对象,被若对象所关联的对象只能存活在到下一次的垃圾回收之前,用WeakReference类实现。
-
虚引用:最弱的,虚引用不会对对象的生存时间存在影响。使用PhantomReference
2.垃圾回收算法(重点):
1.标记-清除算法:效率低,空间碎片多
2.复制算法:每次只使用eden区和一个servivor区,
3.标记整理算法:
4.分代收集算法:
3.几种垃圾回收器:1.Serial: 最基本的,client模式下默认的新生代收集器
2.ParNew:Serial的多线程版,server模式下首选的新生代收集器。只有前面这两个可以和CMS合用
3.Parallel Scavenge:新生代;复制算法。关注吞吐量。
4.Serial Old: Serial老年代版本:标记-整理,一般用于client,1,与Parallel Scavenge搭配 作为CMS的后备预案。
5.Parallel Old :Parallel Scavenge的老年代版本。 标记-整理
只有CMS和G1可以和应用程序并发执行,前面的只是支持多线程而已。
6.CMS:标记-清除。获取最短回收时间为目标。低停顿,比较可以的。特点:对cpu资源敏感,无法处理浮动垃圾(在gc过程中产生的新垃圾不能回收,等下次),大量的空间碎片产生(标记-清除)。Cms只能和serial和parnew用,不能和parallel scavenge合用。
详解cms:清理过程: -
初始标记:标记GC Roots直接关联的对象,速度快。Stop the world
-
并发标记:GC roots tracing :相当于对GC roots 用可达性算法间接关联。
-
重新标记:修正并发标记期间因用户程序运行而导致标记变动的记录。Stop the world
-
并发清除:内存的回收过程和程序可以并发执行。
7.G1(在jdk1.7已经使用):科技前沿,面向服务端应用的。特点:并行和并发,分代收集,空间整合,可预测的停顿(划分各个region。维护一个优先列表)。
将整个堆划分成多个大小相等的独立区域(region),虽然还保留新生代和老年代的概念,但是不再物理隔离,都是一部分region的。
G1跟踪各个region的垃圾堆的价值大小(回收所获得的空间以及回收所需的时间的经验值)。后台维护一个优先列表,优先回收价值大的,提高收集的效率。
G1的回收过程和CMS是基本是一样的。 -
初始标记:GC Roots直接关联,stop 耗时短
-
并发标记:可达性分析 耗时较长,并发,
-
最终标记:修正, stop ,耗时短
-
筛选清除:对各个region的回收价值排序,根据用户所期望的GC停顿时间一起并发执行。
4.内存分配和回收策略:
1.对象优先在Eden分配
2.大对象(很长的字符串和数组)直接进入老年代
3.长期存活的对象(对象年龄计数器:熬过一次minor gc年龄就加1)将进入老年代
4.动态对象年龄判断
5.空间担保分配:失败就full gc