准备工作
- idea
- 新建一个类,编辑类的启动参数
- 添加以下jvm启动参数:-Xss128k -Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\apps
- -Xss128k:设置每个线程的堆栈大小为128k,实验二会用到
- -Xmx5m 设置JVM最大可用内存为5m -Xms5m 设置JVM初始内存为5m
- -XX:+HeapDumpOnOutOfMemoryError 可以让虚拟机在出现内存溢出异常的时候Dump出当前的内存堆转储快照以便进行事后分析
- -XX:HeapDumpPath=D:\apps 指定快照文件存储的位置
实验一:堆内存溢出
public static void main(String[] args) {
List<String> list = new ArrayList<>();
while (true) {
String s = new String("abckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkfsdjks");
list.add(s);
}
}
实验一结果
实验二:堆内存溢出
public static void main(String[] args) {
List<String> list = new ArrayList<>();
while (true) {
String s = new String("abckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkfsdjks" + Math.random());
list.add(s);
}
}
实验二结果
实验三
public static void main(String[] args) {
testStack(0);
}
private static int testStack(int num) {
return testStack(num + 1);
}
实验三结果
栈溢出并不会生成二进制dump文件
可以看到实验一和实验二都生成了后缀名为hprof的Dump文件,有了这个文件,就可以使用MemoryAnalyzer等工具进行分析,排查问题。
MemoryAnalyzer下载地址:eclipse.dev/mat/downloa… 注意,最新版本要求jdk17以上
MemoryAnalyzer旧版本可以点此下载: eclipse.dev/mat/previou…
java.lang.OutOfMemoryError: GC overhead limit exceeded和Java heap space
java.lang.OutOfMemoryError: Java heap space (JVM 堆空间溢出)就是在创建新的对象时, 堆内存中的空间不足以存放新创建的对象,导致此种问题的发生。如果确认不是代码问题,可通过调整JVM启动参数-Xms5m -Xmx5m来解决。
java.lang.OutOfMemoryError: GC overhead limit exceeded:这个错误是由于JVM花费太长时间执行GC且只能回收很少的堆内存时抛出的。根据Oracle官方文档,默认情况下,如果Java进程花费98%以上的时间执行GC,并且每次只有不到2%的堆被恢复,则JVM抛出此错误。
除了这两种OutOfMemoryError异常之外,官方还定义了其它以下几种内存溢出类型:
- java.lang.OutOfMemoryError: Java heap space
- java.lang.OutOfMemoryError: GC Overhead limit exceeded
- java.lang.OutOfMemoryError: Requested array size exceeds VM limit
- java.lang.OutOfMemoryError: Metaspace
- java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?
- java.lang.OutOfMemoryError: Compressed class space
- java.lang.OutOfMemoryError: reason stack_trace_with_native_method
更多的OutOfMemoryError细节可以参考Oracle官方文档 docs.oracle.com/javase/8/do…