圆圆网络 手游攻略 新游动态 oom问题怎么排查,什么是oom异常

oom问题怎么排查,什么是oom异常

时间:2024-05-01 23:41:12 来源:头条 浏览:0

《Java虚拟机规范》 允许除程序计数器之外的虚拟机内存的其他几个运行时区域中发生OutOfMemoryError 异常。

本文主要包括OOM介绍和示例:

java.lang.StackOverflowErrorjava.lang.OutOfMemoryError: Java 堆空间java.lang.OutOfMemoryError: GC 开销超出限制java.lang.OutOfMemoryError--Metaspacejava.lang.OutOfMemoryError: 直接缓冲区内存java.lang.OutOfMemoryError: 无法创建新的本机线程java.lang.OutOfMemoryError:元空间java.lang.OutOfMemoryError: 请求的数组大小超过VM 限制java.lang.OutOfMemoryError: 交换空间不足java.lang.OutOfMemoryError:终止进程或牺牲子进程。经常引发的OOM 异常实际上是错误。

oom问题怎么排查,什么是oom异常

1. StackOverflowError1.1 写一个bug publicclassStackOverflowErrorDemo{publicstaticvoidmain(String[]args){javaKeeper();}privatestaticvoidjavaKeeper(){javaKeeper();}} 我在上一篇文章中详细介绍过

JVM运行时数据区

,JVM虚拟机栈很深。执行一个方法会将其压入堆栈并从堆栈中弹出。从上面的方法可以看出,main方法执行后不断递归,迟早会爆栈。

Exceptioninthread'main'java.lang.StackOverflowErroratom.StackOverflowErrorDemo.javaKeeper(StackOverflowErrorDemo.java:15)1.2 原因分析无限递归调用(最常见的原因) 请始终注意您的代码中是否存在无法终止的循环调用方法。线程由于执行大量方法而耗尽堆栈空间方法内声明了大量局部变量原生代码有在堆栈上分配的逻辑,需要大量内存例如java.net.SocketInputStream.read0需要在堆栈上分配64KB 内存。缓存(64位Linux) 1.3 解决方案:修复导致无限递归调用的异常代码。通过异常堆栈查找重复的代码行。你的程序抛出的,按图检查,修复无限递归bug,检查类之间是否存在循环依赖(如果两个对象互相引用,这个异常会调用toString方法(增加线程栈时也会出现) )使用JVM启动参数-Xss来预留内存空间。一些典型的使用场景需要您执行大量方法或包含大量局部变量。这种情况下,可以适当增加线程堆栈空间限制。 2. Java堆空间Java堆用于存储对象实例。你需要做的就是保证GC根和对象之间有一条可达的路径,以不断创建对象并避免GC清除对象。当对象数量增加时,就会发生内存溢出异常。当总容量达到堆的最大容量限制时。

Java堆内存OOM异常是实际应用中最常见的内存溢出异常。

2.1 写一个bug/*** JVM参数: -Xmx12m*/publicclassJavaHeapSpaceDemo{staticfinalintSIZE=2*1024*1024;publicstaticvoidmain(String[]a){int[]i=newint[SIZE];}} 代码尝试分配对于2M的int数组,如果指定启动参数-Xmx12m,分配的内存将不够用。这类似于将XXXL 编号的对象填充到S 编号的Java 堆空间中。

Exceptioninthread'main'java.lang.OutOfMemoryError:Javaheapspaceatoom.JavaHeapSpaceDemo.main(JavaHeapSpaceDemo.java:13)2.2原因分析请求创建了一个非常大的对象(通常是一个很大的数组)。访问/数据量超出预期。通常是来自上游系统的请求。流量高峰常见在各种促销/闪购活动中,可以结合业务流量指标来检查是否有finalizer过度使用导致对象立即泄漏(内存泄漏),很多对象引用没有释放,JVM无法释放使用它们。当文件等资源被使用但未回收时,自动回收很常见。 2.3 解决方案在大多数情况下,简单地增加JVM 堆通常就足够了。通过-Xmx参数指定内存空间。如果还是不行,您可以参考以下情况进行进一步操作:

对于非常大的对象,可以检查其合理性,例如是否一次查询数据库中的所有结果,而不限制结果数量。业务压力高峰时,添加机器资源、限流、降级。如果出现内存泄漏,就需要改变代码设计,比如查找保留的对象、关闭未释放的连接等。 采访者:我们来谈谈内存泄漏和内存溢出。

请给我额外的知识点。连续三年获得的人终将成为大师~~

内存泄漏和内存溢出内存溢出(内存不足)是指程序申请内存时,没有足够的内存空间来使用,导致内存中断。例如,如果应用了Integer,但应用了Long。数,内存溢出。

内存泄漏意味着程序声明了内存,然后无法释放分配的内存空间。虽然内存泄漏的危害可以忽略不计,但内存泄漏的累积影响却很严重。无论可用内存有多少,它迟早都会被占用。

内存泄漏最终会导致内存耗尽。

3.超出GC开销限制JVM有内置的垃圾收集机制GC,因此Java用户不必手动编写代码来分配和释放内存,但是Java进程如果花费超过%的时间来运行GC ,少于2% 的内存被回收,并且此操作连续重复5 次,您将收到抛出java.lang.OutOfMemoryError:GC 开销限制超出错误(一般与垃圾收集(也称为开销)相关)。简而言之,您的应用程序实际上耗尽了所有可用内存,而GC 无法回收它。

如果没有抛出GC Overhead Limit Exed 错误,那么GC 清理掉的内存会很快再次被填满,迫使GC 再次运行。这是一个恶性循环,导致CPU使用率100%,GC为零。影响。

3.1 写出导致此错误的错误示例。事实上,如果你创建一个无限循环并将数据添加到列表或映射中,完整的GC将继续下去,直到变得无法忍受为止。容易找到。向地图添加1,000 个元素。

/*** JVM参数:-Xmx14m -XX:+PrintGCDetails*/publicclassKeylessEntry{staticclassKey{Integerid;Key(Integerid){this.id=id;}@OverridepublicinthashCode(){returnid.hashCode();}}publicstaticvoidmain(String[ ]args){Mapm=newHashMap();while(true){for(inti=0;i1000;i++){if(!m.containsKey(newKey(i))){m.put(newKey(i),' Number:'+i);}}System.out.println('m.size()='+m.size());}}}.m.size()=54000m.size()=55000m.从size()=56000Exceptioninthread'main'java.lang.OutOfMemoryError:GCoverheadlimitexceeded输出中可以看出,1000的数据限制不起作用,并且地图容量远远超过1000,最终导致了所需的错误。 class Key 只重写hashCode() 方法,但不重写equals() 方法。使用containsKey() 方法时实际上存在问题,因此它会不断向HashMap 添加Key,直到GC 无法再清理它们为止。

面试官又来了。下面讲一下HashMap的原理以及为什么需要同时实现equals和hashcode。

运行这个程序时最终出现的错误也和JVM配置有关,如果配置的堆内存特别小,会直接报到Java堆空间。如果您的资源有限,您可能无法准确预测程序停止的具体原因,因为它很可能被此错误阻止。

3.2 解决方案:添加JVM参数-XX:-UseGCOverheadLimit。不建议这样做。它实际上并不能解决问题。只需推迟异常并检查项目中是否有大量无限循环或使用大量内存的代码。优化代码转储内存分析,检查是否存在内存泄漏。如果遇到内存泄漏,请增加内存。 4.直接缓冲存储器在使用NIO时,经常需要使用ByteBuffer来读取或写入数据。这是一种基于Channel 和Buffer 的I/O 类型,该方法允许您使用本机函数库直接分配堆外内存,并通过存储在Java 堆中的DirectByteBuffer 对象作为对此内存的引用。在某些情况下,这可以避免在Java 堆和本机之间来回复制数据,从而提高性能。

Java允许应用程序通过Direct ByteBuffers直接访问堆外内存,许多高性能程序将Direct ByteBuffers与内存映射文件结合起来以实现快速IO。

4.1 编写bug ByteBuffer.allocate(capability)分配JVM堆内存,因此会受到GC的影响,并且由于需要内存复制,速度相对较慢。 ByteBuffer.allocateDirect(capability) 分配操作系统本地内存。这不是必需的,因此不属于GC的管辖范围,因此复制内存的速度相对较快。如果本地内存持续分配,而堆内存很少使用,则JVM不需要进行GC,即使堆内存足够,DirectByteBuffer对象也可能会耗尽本地内存,导致OOM。溢出。

/*** 虚拟机选项: -Xms10m,-Xmx10m,-XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m*/publicclassDirectBufferMemoryDemo{publicstaticvoidmain(String[]args){System.out.println('maxDirectMemoryis:'+sun.misc.VM.maxDirectMemory ()/1024/1024+'MB');//ByteBufferbuffer=ByteBuffer.allocate(6*1024*1024);ByteBufferbuffer=ByteBuffer.allocateDirect(6*1024*1024);}}最大直接内存,默认自计算机内存是1/4,设置一个小点并且使用超过这个值的直接内存会导致OOM。

maxDirectMemoryis:5MBExceptioninthread'main'java.lang.OutOfMemoryError:Directbuffermemory4.2 解决方案在Java中,只能通过ByteBuffer.allocateDirect方法使用Direct ByteBuffer。因此,您可以通过Arthas等在线诊断工具拦截该方法,看看NIO是否被直接或间接使用。 netty、jetty等通过启动参数-XX:MaxDirectMemorySize调整Direct ByteBuffer限制。检查JVM参数是否有-XX:+DisableExplicitGC选项。如果存在,请将其删除,因为此参数会禁用System.gc()。检查你的堆外内存使用代码是否存在内存泄漏,或者通过反射调用sun.misc.Cleaner的clean()方法,积极回收Direct ByteBuffers所占用的内存空间,请释放它。升级配置5. 无法创建新的本机线程。每个Java线程都必须占用一定的内存空间。当JVM请求底层操作系统创建新的native线程时,会报类似如下的错误:没有分配足够的资源。

5.1 编写bug publicstaticvoidmain(String[]args){while(true){newThread(()-{try{Thread.sleep(Integer.MAX_VALUE);}catch(InterruptedExceptione){}}).start();}}初始化VM时出错java.lang.OutOfMemoryError:unabletocreatenewnativethread5.2 原因分析当JVM无法请求操作系统创建native线程时,抛出Unableto createnewnativethread。常见原因包括以下几类:

线程数超过操作系统最大线程数(取决于平台) 线程数超过kernel.pid_max(仅重新启动) 本机内存不足。这个问题的大致流程主要是:下一步:JVM 中的应用程序请求创建新的Java 线程。 JVM 本机方法代理请求并要求操作系统创建本机线程。操作系统尝试创建一个新的本机线程并为其分配内存。 如果操作系统的虚拟内存耗尽,或者由于32 位进程的地址空间限制,操作系统将拒绝此本机内存分配,并且JVM 会抛出java.lang.OutOfMemoryError:Unableto createnewnativethread 错误。 5.3 解决方案找到一种方法来减少程序中创建的线程数量,分析您的应用程序是否确实需要创建许多线程,如果确实需要创建许多线程,请通过以下方式增加最大线程数:运行ulimia。 -a 要显示最大线程数限制,请使用ulimit -u xxx。调整最大线程数限制6. Permgen 空间出现在MetaspaceJDK 1.8 之前。此错误意味着永久代已满。加载的类太多或它们的大小太大。 1.8中已经删除了持久代,因此不再出现这种异常情况。

Metaspace是HotSpot方法区的实现。与持久代最大的区别是元空间使用本地内存而不是虚拟机内存。但是,如果本地内存已满,则会引发异常。

6.1 写一个bug/***JVMOptions:-XX:MetaspaceSize=10m-XX:MaxMetaspaceSize=10m*/publicclassMetaspaceOOMDemo{publicstaticvoidmain(String[]args){while(true){Enhancerenhancer=newEnhancer();enhancer.setSuperclass(MetaspaceOOMDemo.class);enhancer .setUseCache(false);enhancer.setCallback((MethodInterceptor)(o,method,objects,methodProxy)-{//动态代理创建对象returnmethodProxy.invokeSuper(o,objects);});enhancer.create ();}}使用Spring的GCLib动态创建对象

Exceptioninthread'main'org.springframework.cglib.core.CodeGenerationException:java.lang.OutOfMemoryError--Metaspace6.2解决方法方法空间溢出也是一般的内存溢出异常。执行过程中经常产生大量动态类的应用场景需要特别注意回收这些类。除了上面提到的GCLib字节码扩展和动态语言之外,这样的场景还可以用于使用大量JSP或者动态生成JSP文件的应用程序(这在传统软件行业中早已存在),这在基于OSGi 的应用程序中也很常见。 (不同加载器加载的相同类文件也被认为是不同的类)等等。

一般来说,在JDK8中生成方法区域并不容易,但是HotSpot提供了几个用于配置元空间的参数,可以起到积极的作用。

-XX:MaxMetaspaceSize 设置元空间的最大值。默认为-1,表示没有限制(仍受本地内存大小限制)。 -XX:MetaspaceSize 指定元空间的初始空间大小(以字节为单位)。当达到这个值时,就会触发GC。当您键入unload 时,收集器会调整值-XX:MinMetaspaceFreeRatio 控制GC 后剩余元空间容量的最小百分比。这减少了由于缺乏元空间而导致的垃圾收集频率。类似的还有MaxMetaspaceFreeRatio 7。请求的数组大小超过VM限制7.1 写一个bug public static void main(String[]args){int[]arr=newint[Integer.MAX_VALUE];} 这个比较简单。构建一个非常大的数组会导致OOM。我不再多说了。

Exceptioninthread'main'java.lang.OutOfMemoryError:RequestedarraysizeexceedsVMlimitJVM限制数组的最大长度。此错误表明程序请求创建的数组超出了最大长度限制。

在JVM 为数组分配内存之前,它会检查正在分配的数据结构(通常是Integer.MAX_VALUE-2)在系统内是否可寻址。

这种问题比较少见,但是你通常会检查你的代码,看看你的业务是否需要创建这么大的数组,是否可以将它们拆分成多个块并批量运行,你需要检查。

8. 当我启动一个缺少交换空间的Java 应用程序时,它会分配有限的内存。此限制由-Xmx 和其他类似启动参数指定。

如果JVM 请求的总内存大于可用物理内存,则操作系统开始将内容从内存交换到硬盘驱动器。

此错误表明所有可用的虚拟内存已用完。虚拟内存由两部分组成:物理内存和交换空间。

我以前从未见过这样的错误。

9. 杀死进程或牺牲其子进程操作系统基于进程的概念。这些进程由多个内核作业处理。其中之一称为“内存不足杀手”,当可用内存严重不足时,它会“杀死”某些进程。 OOM Killer 对所有进程进行评分并“杀死”那些低分的进程。具体评分规则请参见Linux OOM Killer Survival。

与其他OOM 错误不同,Killprocessorssacrifice child 错误不是在JVM 级别触发,而是在操作系统级别触发。

9.1 原因分析默认情况下,Linux 内核允许进程请求比系统可用内存更多的内存。这种“峰移复用”方法可以更有效地利用系统资源。

不过,这种做法并不能避免一定的“超卖”风险。例如,某些进程继续占用系统内存,没有为其他进程留下可用的内存。这时,系统会自动激活OOM Killer,它会寻找分数较低的进程并“杀死”它们以释放内存资源。

9.2 解决方案:升级服务器配置/隔离部署,避免冲突和OOM Killer调优。最后附上大神“Yahai”的照片。

雅伊

参考及致谢《深入理解 Java 虚拟机 第 3 版》

https://plumbr.io/内存不足错误

https://yq.aliyun.com/articles/711191

https://github.com/StabilityMan/StabilityGuide/blob/master/docs/diagnosis/jvm/Exception

标题:oom问题怎么排查,什么是oom异常
链接:https://yyuanw.com/news/xydt/13346.html
版权:文章转载自网络,如有侵权,请联系删除!
资讯推荐
更多
阴阳师4月22日更新内容:帝释天上线技能调整,红莲华冕活动来袭

阴阳师4月22日更新内容:帝释天上线技能调整,红莲华冕活动来袭[多图],阴阳师4月22日更新的内容有哪些?版本更新

2024-05-01
四川电视台经济频道如何培养孩子的学习习惯与方法直播在哪看?直播视频回放地址

四川电视台经济频道如何培养孩子的学习习惯与方法直播在哪看?直播视频回放地址[多图],2021四川电视台经济频

2024-05-01
湖北电视台生活频道如何培养孩子的学习兴趣直播回放在哪看?直播视频回放地址入口

湖北电视台生活频道如何培养孩子的学习兴趣直播回放在哪看?直播视频回放地址入口[多图],湖北电视台生活频道

2024-05-01
小森生活金币不够用怎么办?金币没了不够用解决方法

小森生活金币不够用怎么办?金币没了不够用解决方法[多图],小森生活金币突然就不够用的情况很多人都有,金币没

2024-05-01