打印详细的GC信息命令:-XX:+PrintGCDetails;监测工具:VisualVM
- 模拟大对象,触发GC
- -XX:+PrintGCDetails 打印GC信息
- VisualVM启动
package com.lyb269.jvm.gc;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 模拟触发GC,结合VisualVM工具监测变化
* -XX:+PrintGCDetails
*/
public class MonitorGcTest {
@Test
public void testOOM(){
List<byte[]> bsList = new ArrayList<>();
for (int i = 0; i < 10000; i++){
// 模拟大对象
byte[] bs = new byte[1000 * 1024 * 1024];
bsList.add(bs);
}
//抛出异常 java.lang.OutOfMemoryError: Java heap space
// bs是局部变量,存在java栈里,这里OOM是java栈内存溢出了
}
@Test
public void testGc(){
List<byte[]> bsList = new ArrayList<>();
for (int i = 0; i < 400; i++){
// 模拟一个对象20M
byte[] bs = new byte[20 * 1024 * 1024];
bsList.add(bs);
System.out.println("当前时间:"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
try {
//3秒增加一次,利于检测
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// GC (Allocation Failure)触发新生代的GC
// Full GC 触发整个GC,包括新生代,老年代,永久代
//GC信息打印如下:
//[GC (Allocation Failure) [PSYoungGen: 42883K->64K(62464K)] 1990911K->1989076K(2074624K), 0.0274901 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]
//[Full GC (Ergonomics) [PSYoungGen: 64K->0K(62464K)] [ParOldGen: 1989012K->1988964K(2099200K)] 1989076K->1988964K(2161664K), [Metaspace: 10593K->10593K(1058816K)], 0.2556522 secs] [Times: user=0.55 sys=0.01, real=0.26 secs]
//上述一直循环打印GC信息,等到内存满时,触发OOM:OutOfMemoryError
}
}
上面代码,模拟一个对象20M,然后3秒创建一次,利于监测.控制台打印信息如代码.
刚开始,GC情况如下:
伊甸区eden内存在上升,同时幸存1区Survivor1内存也在上升.但是还未达到回收的地步.
如上图所示:新生代在经过几次的回收没有被回收掉,大量的大对象转向老年代,老年代的内存占用在上升.同时控制台也一直在打印GC信息,循环回收,
GC一直在不间断的回收,但是由于大量的活跃对象占用,慢慢的占满了老年代内存.
如上老年代内存已经占满,触发内存溢出OOM:OutOfMemoryError
如上图:老年代内存溢出,触发OOM