OOM原因
1. 堆溢出
报错信息:
java.lang.OutOfMemoryError: Java heap space
-
代码中可能存在大对象分配,无法获得足够的内存分配
-
可能发生内存泄露,导致内存被无效占用以至于耗尽
2. 永久代/元空间溢出
报错信息:
java.lang.OutOfMemoryError: PermGen space
java.lang.OutOfMemoryError: Metaspace
-
在Java7之前,频繁的使用String.intern()方法
-
代码中存在大量的反射操作,导致方法区被撑爆,无法卸载
3. 方法栈溢出
报错信息:
java.lang.OutOfMemoryError : unable to create new native Thread
每个 Java 线程都需要占用一定的内存空间,当 JVM 向底层操作系统请求创建一个新的 native 线程时,如果没有足够的资源分配就会报此类错误。出现这种异常,基本上都是创建的了大量的线程导致的。
4. swap溢出
报错信息 :
java.lang.OutOfMemoryError: Out of swap space
这种情况一般是操作系统导致的,可能的原因有:
-
swap 分区大小分配不足;
-
其他进程消耗了所有的内存。
5. 本地方法溢出
报错信息 :
java.lang.OutOfMemoryError: stack_trace_with_native_method
本地方法在运行时出现了内存分配失败,和之前的方法栈溢出不同,方法栈溢出发生在 JVM 代码层面,而本地方法溢出发生在JNI代码或本地方法处。
6. GC overhead limit exceeded
报错信息:
java.lang.OutOfMemoryError:GC overhead limit exceeded
超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常。
- 项目中可能有大量的死循环或有使用大内存的代码
- 存在内存泄露
7. Requested array size exceeds VM limit
报错信息:
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
JVM 限制了数组的最大长度,该错误表示程序请求创建的数组超过最大长度限制。
8. Direct buffer memory
报错信息:
java.lang.OutOfMemoryError: Direct buffer memory
Direct ByteBuffer 的默认大小为 64 MB,一旦使用超出限制,就会抛出此错误。
JVM监控工具介绍
1. jps命令
显示指定系统内所有的java虚拟机系统
-l
:输出进程ID和应用主类的完整路径;-v
:输出向jvm传递的参数,此处展示为idea中显式配置的VM-options参数,其他内容自行查看即可;-m
:输出向main方法传递的参数,服务启动前可以在idea的Program-arguments配置;
2. jinfo命令
查看和调整虚拟机参数。在命令后面带pid进程号,可以输出指定进程的配置信息。
-sysprops
:输出 Java System Properties 参数;-flags
:输出 VM Flags 参数;
3. jstat命令
输出JVM的监控指标
-gc
:输出java堆相关信息;-gcutil
:输出java堆各个区域使用百分比;
4. jstack命令
输出指定进程当前时刻在JVM中的线程信息
5. jmap命令
输出指定进程的内存中对象映射信息,或者堆的关键信息、内存的使用统计、GC算法、配置、类的实例信息及内存占用等
-heap
:输出java堆详细信息;-dump
:输出java堆内存快照;
6. jconsole
Java内置的JVM性能监控工具,在熟悉上述的命令行工具之后,对于该可视化工具的使用不会太陌生,在命令中可以查看到的默认参数或者应用自定义配置,在该工具中也可以找到,并且以图形化的方式呈现;
7. jvisualvm
VisualVM 提供了一个可视界面,用于查看JVM上运行的基于 Java 技术的应用程序的详细信息。可以查看本地应用程序或远程主机上运行的应用程序的相关数据。此外,还可以捕获有关 JVM 软件实例的数据,并将该数据保存到本地系统,以供后期查看或与其他用户共享。
通过jvisualvm定位OOM问题
获取dump文件
注意导出文件占用内存很大的时候,可能会导不出来
-
方式一:提前配置jvm参数,在系统挂了后会在指定目录下生成dump文件
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./ (导出路径)
-
方式二:使用命令行导出
jmap -dump:format=b,file=demo.hprof pid
通过jvisualvm工具装载dump文件
查看内存占用最高的业务对象,并找到GCRoot并查看线程栈从而定位问题
通过Arthas工具定位问题
执行如下命令下载arthas-boot.jar
,再用java -jar
命令启动:
wgethttps://arthas.aliyun.com/arthas-boot.jar; java-jararthas-boot.jar
arthas-boot是Arthas的启动程序,它启动后,会列出所有的Java进程,用户可以选择需要诊断的目标进程。
使用dashboard 命令可以查看当前系统的实时数据面板。可以查看到CPU、内存、GC、运行环境等信息。
使用 sc 命令来查找JVM里已加载的类,通过-d参数,可以打印出类加载的具体信息,很方便查找类加载问题。