参考《深入理解JVM》这本书,总结一下面试中常备问到的问题
5.如何判断对象可以被回收?
1.引用计数(有bug 不能解决循环引用的问题)
2.可达性分析:
可选做GC Roots的对象包括以下几种:
虚拟机栈(栈帧中局部变量表)中引用的数据
方法区中静态属性引用的对象(static)
方法区中常量引用的对象(final)
本地方法栈(native方法)中引用的对象
6.引用的分类
强引用:GC时不会被回收
软引用:描述有用但不是必须的对象,在发生内存溢出异常之前被回收
弱引用:描述有用但不是必须的对象,在下一次GC时被回收
虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用PhantomReference实现虚引用,虚引用用来在GC时返回一个通知。
7.判断一个对象应该被回收
1.该对象没有与GC Roots相连
2.该对象没有重写finalize()方法或finalize()已经被执行过则直接回收(第一次标记)
、否则将对象加入到F-Queue队列中(优先级很低的队列)在这里finalize()方法被执行,之后进行第二次标记,如果对象仍然应该被GC则GC,否则移除队列。(在finalize方法中,对象很可能和其他 GC Roots中的某一个对象建立了关联,finalize方法只会被调用一次,且不推荐使用finalize方法)
8.回收方法区
方法区回收价值很低,主要回收废弃的常量和无用的类。
如何判断无用的类:
1.该类所有实例都被回收(java堆中没有该类的对象)
2.加载该类的ClassLoader已经被回收
3.该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方利用反射访问该类
1.标记-清除
先标记再清除、效率不高、产生碎片。
2.复制算法
内存划分为大小相等的两块,每次只使用一块,当这一块用完了就将对象中存活的对象复制到另一块上边。
效率较高、有内存被空闲不能完全利用。
商业虚拟机目前使用这种算法回收新生代。用8:1:1来分配eden:From Survivor: To Survivo,即可以使用90%的对象,survivor空间不够时需要老年代分配担保
3.标记-整理
标记之后将所有存活的对象向一端移动,不产生碎片