@ninjaz
2018-05-13T07:32:01.000000Z
字数 4998
阅读 28
GC
- 哪里需要回收?
- 什么时候回收?
- 如何回收?
线程隔离的内存区域(程序计数器、虚拟机栈、本地方法栈),线程结束时内存回收,无需多虑回收问题。
可达性分析
GCRoots到这个对象不可达时,此对象需要回收
Object obj = new Object();
永不回收被引用对象SoftReference
类。WeakReference
类PhantomReference
类不可达对象不一定回收,回收的对象至少经历两次标记过程
finalize()
或者finalize()
方法已被虚拟机调用过,则视为“没有必要执行”finalize()
方法,则放入F-Queue队列中,稍后虚拟机建立低优先级的Finalizer线程去执行它(并不承诺等待它运行结束,避免执行缓慢和死循环的问题)。finalize()
方法是对象自我救赎的最后机会。执行后只需和引用链上的任何对象关联即可。
/**
* 此代码演示了两点:
* 1.对象可以在被GC时自我拯救。
* 2.自救机会只有一次,因一个对象的finalize()方法最多只会被系统自动调用一次
*/
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK = null;
public void isAlive() {
System.out.println("yes,i am still alive:)");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method executed!");
FinalizeEscapeGC.SAVE_HOOK = this;
}
public static void main(String[] args) throws Throwable {
SAVE_HOOK = new FinalizeEscapeGC();
//对象第一次成功拯救自己
SAVE_HOOK = null;
System.gc();
//因为finalize方法优先级很低,所以暂停0.5秒以等待它
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no,i am dead:(");
}
//下面这段代码与上面的完全相同,但是这次自救却失败了
SAVE_HOOK = null;
System.gc();
//因为finalize方法优先级很低,所以暂停0.5秒以等待它
Thread.sleep(500);
if (SAVE_HOOK != null) {
SAVE_HOOK.isAlive();
} else {
System.out.println("no,i am dead:(");
}
}
}
SAVE_HOOK对象的finalize()方法确实被GC收集器触发过,并且在被收集前成功逃脱了。但不建议使用该方法
方法区又称HotSpot的永久代;主要回收废弃常量和无用类
无用类需同时满足:
1. 该类所有实例已被回收(即Java堆中不存在该类实例)
2. 加载该类的ClassLoader已被回收
3. 该类对应的java.lang.Class对象没有在任何地方被引用,无法再任何地方用过反射访问该类的方法
- 新生代 一般被分为: 1 * Eden(较大) + 2 * Survivor(较小)
- Eden : Survivor = 8 : 1
- 由于内存不够,老年代一般不直接选用复制收集算法
一般老年代使用
- Java堆 分为 新生代 + 老年代
- 新生代用复制算法;老年代用标记-清理or标记-整理
如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现
并行:多条垃圾收集线程并行工作,但用户线程等待
并发:用户线程与垃圾线程同时执行
- 新生代GC(Minor GC):非常频繁,一般回收速度也比较快。
- 老年代GC(Major GC/Full GC):经常会伴随至少一次的Minor GC(但非绝对的,在Parallel Scavenge收集器的收集策略里就有直接进行
Major GC的策略选择过程)。 Major GC的速度一般会比Minor GC慢10倍以上。