- OOM的原因
- JVM内存模型
- 最常见的OOM的类型
- 7种OOM类型详解
- java.lang.OutOfMemoryError: Java heap space
- java.lang.OutOfMemoryError: reason stack_trace_with_native_method
- java.lang.OutOfMemoryError: Compressed class space
- java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?
- java.lang.OutOfMemoryError: Metaspace
- java.lang.OutOfMemoryError: Requested array size exceeds VM limit
- java.lang.OutOfMemoryError: GC Overhead limit exceeded
- 文章列表
- 经典案例
- 问题求助
OOM的原因
什么是OOM?
OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”
为什么会OOM?
为什么会没有内存了呢?原因不外乎有两点:
1)分配的少了:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。
2)应用用的太多,并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。
内存泄漏和溢出
内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了。
内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。
JVM内存模型
按照JVM规范,JAVA虚拟机在运行时会管理以下的内存区域:
程序计数器
:当前线程执行的字节码的行号指示器,线程私有。JAVA虚拟机栈
:每个Java方法的执行对应着一个栈帧的进栈和出栈的操作。本地方法栈
:类似“ JAVA虚拟机栈 ”,但是为native方法的运行提供内存环境。JAVA堆
:对象内存分配的地方,内存垃圾回收的主要区域,所有线程共享。分为新生代,老生代。方法区
:用于存储已经被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Hotspot中的“永久代”。运行时常量池
:方法区的一部分,存储常量信息,如各种字面量、符号引用等。直接内存
:并不是JVM运行时数据区的一部分, 可直接访问的内存, 比如NIO会用到这部分。
最常见的OOM的类型
按照JVM规范,除了程序计数器不会抛出OOM外,其他各个内存区域都可能会抛出OOM。
最常见的OOM情况有以下三种:
java.lang.OutOfMemoryError: Java heap space
java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。对于内存泄露,需要通过内存监控软件查找程序中的泄露代码,而堆大小可以通过虚拟机参数-Xms,-Xmx等修改。
java.lang.OutOfMemoryError: PermGen space
java永久代溢出,即方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出。
java.lang.StackOverflowError
不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。
7种OOM类型详解
java.lang.OutOfMemoryError: Java heap space
此错误并不一定意味着内存泄漏。
可能的原因:
- 指定的堆大小(或默认大小,如果没有指定)对应用程序来说是不够的
- 应用程序无意中持有对长生命周期的对象的引用
- 过度使用终结器(finalize)
java.lang.OutOfMemoryError: reason stack_trace_with_native_method
如果错误消息的详细信息部分是“reason stack_trace_with_native_method”,并且打印了一个堆栈跟踪,其中顶部帧是本机方法,那么这表明本机方法遇到了分配失败。这与上一条消息的区别在于,分配失败是在Java本机接口(JNI)或本机方法中检测到的,而不是在JVM代码中。操作:如果抛出此类OutOfMemoryError异常,您可能需要使用操作系统的本机实用程序来进一步诊断问题。java.lang.OutOfMemoryError: Compressed class space
在64位平台上,指向类元数据的指针可以用32位偏移量(使用UseCompressedOops)表示。这由命令行标志UseCompressedClassPointers(默认情况下打开)控制。如果使用UseCompressedClassPointers,则类元数据的可用空间量将固定在CompressedClassSpaceSize的量上。如果UseCompressedClassPointers所需的空间超过CompressedClassSpaceSize,则抛出带有详细信息压缩类空间的java.lang.OutOfMemoryError。操作:增加CompressedClassSpaceSize以关闭UseCompressedClassPointers。注意:CompressedClassSpaceSize的可接受大小有界限。例如-XX: CompressedClassSpaceSize=4g,超过可接受的界限将导致消息,例如CompressedClassSpaceSize4294967296无效;必须在1048576和3221225472之间。
注意:有多种类元数据——klass元数据和其他元数据。只有klass元数据存储在CompressedClassSpaceSize的边界空间中。其他元数据存储在Metaspace中。java.lang.OutOfMemoryError: request size bytes for reason. Out of swap space?
似乎是一个OutOfMemoryError异常。然而,当本机堆的分配失败且本机堆可能接近耗尽时,Java HotSpot VM代码会报告此明显的异常。消息指示失败的请求的大小(以字节为单位)和内存请求的原因。通常原因是报告分配失败的源模块的名称,尽管有时这是实际原因。如果引发此类OutOfMemoryError异常,您可能需要使用操作系统上的故障诊断实用程序来进一步诊断问题。java.lang.OutOfMemoryError: Metaspace
Java类元数据(Java类的虚拟机内部表示)分配在本机内存中(此处称为元空间)。如果类元数据的元空间已用尽,则会抛出带有MetaSpace详细信息的java.lang.OutOfMemoryError异常。可用于类元数据的元空间量受命令行上指定的参数MaxMetaSpaceSize的限制。当类元数据所需的本机内存量超过MaxMetaSpaceSize,将抛出带有详细信息MetaSpace的java.lang.OutOfMemoryError异常。操作:如果在命令行上设置了MaxMetaSpaceSize,请增加其值。MetaSpace从与Java堆相同的地址空间分配。缩小Java堆的大小将为MetaSpace提供更多空间。只有当Java堆中空闲空间过剩时,这是一个正确的权衡。有关“掉期空间”详细信息,请参阅以下操作。java.lang.OutOfMemoryError: Requested array size exceeds VM limit
请求的数组大小超过VM限制”表示应用程序(或该应用程序使用的API)试图分配大于堆大小的数组。例如,如果应用程序尝试分配512 MB的数组,但最大堆大小为256 MB,则将引发OutOfMemoryError,原因为请求的数组大小超过VM限制。操作:通常问题要么是配置问题(堆大小太小),要么是导致应用程序尝试创建大型数组的错误(例如,当使用计算错误大小的算法计算数组中的元素数量时)。java.lang.OutOfMemoryError: GC Overhead limit exceeded
GC Overhead limit exceeded表示垃圾收集器一直在运行,Java程序进展非常缓慢。在垃圾收集后,如果Java进程花费了大约98%以上的时间进行垃圾收集,并且它正在恢复不到2%的堆,并且到目前为止一直在进行最后5个(编译时间常数)连续垃圾收集,则会引发java.lang.OutOfMemoryError。之所以引发此异常,是因为实时数据的数量几乎不适合Java堆,几乎没有空闲空间用于新的分配。行动:增加堆大小。超过GC开销限制的java.lang.OutOfMemoryError异常可以通过命令行标志-XX:-UseGCOverheadLimit
关闭。
文章列表
Java基础文档,最官方的解释:
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks002.html
社区内小伙伴翻译版:https://heapdump.cn/article/3091503
几篇大佬的个人理解和分析:
gshine2012年的一篇,非常经典:https://heapdump.cn/article/3059968
社区专家占小狼的一篇也非常全面:https://heapdump.cn/article/248921
笨神的源码分析:https://heapdump.cn/article/297323
geekoftaste从垃圾回收开始,理完了mom:https://heapdump.cn/article/1958599
公与视频课程之oom开篇:https://heapdump.cn/c/3046381/lecture/3046939
额外兴趣阅读:
利用弱引用和软引用来避免OOM:https://heapdump.cn/article/3064956
JVM内存分区的理论分析:https://www.cnblogs.com/dolphin0520/p/3613043.html
GC回收机制源码解析:
https://heapdump.cn/article/1928984
https://heapdump.cn/article/1933770
https://heapdump.cn/article/1980741
https://heapdump.cn/article/2016492
经典案例
1,evictExpiredConnections 配置导致线程数暴涨,导致oom
https://heapdump.cn/article/292449
额外阅读:https://www.heapdump.cn/article/244079 关于线程创建理论
2,OOM案例分析之 gc overhead limit exceeded问题
https://heapdump.cn/article/3094005
3,主线程发生oom后,cpu暴涨800%
https://heapdump.cn/article/315469
4,一个使用 httpasyncclient 产生的oom问题,排查过程很详细
https://heapdump.cn/article/670585
5,一次容器化springboot程序OOM问题探险
https://heapdump.cn/article/1588447
6,fastJson与一起堆内存溢出’血案’
https://heapdump.cn/article/1656271
OOM学习训练营第三天来啦!
今日给大家分享5个典型的案例:
学习起来昂!大家多留言昂!
1,容器内存占用居高不下,频频 OOM
https://heapdump.cn/article/1589003
https://heapdump.cn/article/1692022(续)
2,一次线上CPU100%及应用OOM的排查和解决过程
https://heapdump.cn/article/1665572
3,一次 Java 进程 OOM 的排查分析(glibc 篇)
https://heapdump.cn/article/1709425
4,一次真实的线上OOM问题定位
https://heapdump.cn/article/1725973
5,一则OOM死机故障的处理过程
https://heapdump.cn/article/1842892
https://heapdump.cn/article/1900895 (续)
OOM学习导读第四天,在社区整理了几个简单的问题。
大家有了前面的理论和案例积累,都可以尝试自己去留言回答一下下噢!
5个现场问题:
一个Netty 池问题:
1,https://heapdump.cn/question/2487355
一个指定脚本未运行的问题:
2,https://heapdump.cn/question/380353
一个jvmkill 相关问题:
3,https://heapdump.cn/question/2478021
一个tomcat被系统oom killer的问题:
4,https://heapdump.cn/question/328003
一个系统创建不出线程的问题:
5,https://heapdump.cn/question/322367
3个理论问题:
GC相关的问题:
1,https://heapdump.cn/question/1742746
heap size含义问题:
2,https://heapdump.cn/question/199173
3,java 直接内存回收问题:
https://heapdump.cn/question/1848698
问题求助
Jvm元空间内存OOM
https://heapdump.cn/question/3090582
JVM GC中cardTable相关的问题
https://heapdump.cn/question/3052550
tomcat进程环境变量,对于jni本地调用是否生效
https://heapdump.cn/question/3083032
tomcat 运行javaweb 程序 一段时间就CPU 100% 重启后正常 ,再运行有时几个小时有时一两天cpu 1000%
https://heapdump.cn/question/3078554
jvm cms gc remark不会更加增加STW的时间吗?
https://heapdump.cn/question/3096374