回收策略
触发条件
内存垃圾回收机制主要集中的区域就是线程共享区域:堆和方法区
Minor GC 触发条件非常简单,当 Eden 空间满时,就将触发一次 Minor GC
FullGC 同时回收新生代、老年代和方法区,只会存在一个 FullGC 的线程进行执行,其他的线程全部会被挂起,有以下触发条件:
-
调用 System.gc():
-
在默认情况下,通过 System.gc() 或 Runtime.getRuntime().gc() 的调用,会显式触发 FullGC,同时对老年代和新生代进行回收,但是虚拟机不一定真正去执行,无法保证对垃圾收集器的调用
-
不建议使用这种方式,应该让虚拟机管理内存。一般情况下,垃圾回收应该是自动进行的,无须手动触发;在一些特殊情况下,如正在编写一个性能基准,可以在运行之间调用 System.gc()
-
-
老年代空间不足:
-
为了避免引起的 Full GC,应当尽量不要创建过大的对象以及数组
-
通过 -Xmn 参数调整新生代的大小,让对象尽量在新生代被回收掉不进入老年代,可以通过
-XX:MaxTenuringThreshold
调大对象进入老年代的年龄,让对象在新生代多存活一段时间
-
-
空间分配担保失败
-
JDK 1.7 及以前的永久代(方法区)空间不足
-
Concurrent Mode Failure:执行 CMS GC 的过程中同时有对象要放入老年代,而此时老年代空间不足(可能是 GC 过程中浮动垃圾过多导致暂时性的空间不足),便会报 Concurrent Mode Failure 错误,并触发 Full GC
手动 GC 测试,VM参数:-XX:+PrintGcDetails
public void localvarGC1() {
byte[] buffer = new byte[10 * 1024 * 1024];//10MB
System.gc(); //输出: 不会被回收, FullGC时被放入老年代
}
public void localvarGC2() {
byte[] buffer = new byte[10 * 1024 * 1024];
buffer = null;
System.gc(); //输出: 正常被回收
}
public void localvarGC3() {
{
byte[] buffer = new byte[10 * 1024 * 1024];
}
System.gc(); //输出: 不会被回收, FullGC时被放入老年代
}
public void localvarGC4() {
{
byte[] buffer = new byte[10 * 1024 * 1024];
}
int value = 10;
System.gc(); //输出: 正常被回收,slot复用,局部变量过了其作用域 buffer置空
}