针对目前大家对OOM的类型不太熟悉,那么来总结一下各种OOM出现的情况以及解决方法。把各种OOM的情况列出来,然后逐一进行代码编写复现和提供解决方法。

1. 堆溢出-java.lang.OutOfMemoryError: Java heap space。

2. 栈溢出-java.lang.OutOfMemorryError。

3. 栈溢出-java.lang.StackOverFlowError。

4. 元信息溢出-java.lang.OutOfMemoryError: Metaspace。

5. 直接内存溢出-java.lang.OutOfMemoryError: Direct buffer memory。

6. GC超限-java.lang.OutOfMemoryError: GC overhead limit exceeded。

0x01: 堆溢出异常,相信大家很常见。即堆内对象不能进行回收了,堆内存持续增大,这样达到了堆内存的最大值,数据满了,所以就出来了。我们直接放溢出的代码样例。需要设置好idea的VM Options: -Xmx100m,这样设置为最大堆内存,这样运行起来就很快就出来错误了。

package oom;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;public class HeapOOM {    static class OOMObject {    }    public static void main(String[] args) throws InterruptedException {        List list = new ArrayList<>();        while(true) {//            TimeUnit.MILLISECONDS.sleep(1);            list.add(new OOMObject());        }    }}

运行的异常如下,代码直接就出来我们看到的异常了。

/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -Xmx100mException in thread "main" java.lang.OutOfMemoryError: Java heap space    at java.util.Arrays.copyOf(Arrays.java:3210)    at java.util.Arrays.copyOf(Arrays.java:3181)    at java.util.ArrayList.grow(ArrayList.java:261)    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)    at java.util.ArrayList.add(ArrayList.java:458)    at oom.HeapOOM.main(HeapOOM.java:21)Process finished with exit code 1

细心的小伙伴可以发现代码中设置了一个休眠,目的是看一下堆内存的结构和数据图。将休眠代码打开,然后打开JDK自带的jconsole命令,连接上之后看一下概览图,通过下图发现堆内存持续不断的增长。

打开内存界面,看一下内存,然后点一下GC按钮,这个时候会有一些类进行回收,但是还是会继续增长,看一下下面的图。

点开信息标签看一下。经过几次GC回收之后,类的数据量还是变化不大,说明没有进行回收。

以上这种情况的解决方法就是找到问题点,分析哪个地方是否存储了大量类没有被回收的情况,通过JMAP命令将线上的堆内存导出来后进行分析。

0x02: 看一下栈溢出的情况,下面的代码就是无限的创建线程,直到没法再创建线程。

package oom;import java.util.concurrent.TimeUnit;/** * @Date 2020-07-18 */public class StackOOM {    public static void infiniteRun() {        while(true) {            Thread thread = new Thread(() -> {                while (true) {                    try {                        TimeUnit.HOURS.sleep(1);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            });            thread.start();        }    }    public static void main(String[] args) {        infiniteRun();    }}

抛出来的异常如下,如果真的需要创建线程,我们需要调整帧栈的大小-Xss512k,默认帧栈大小为1M,如果设置小了,可以创建更多线程。

/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -Xss512k Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread    at java.lang.Thread.start0(Native Method)    at java.lang.Thread.start(Thread.java:717)    at oom.StackOOM.infiniteRun(StackOOM.java:24)    at oom.StackOOM.main(StackOOM.java:29)Process finished with exit code 130 (interrupted by signal 2: SIGINT)

以上这种情况是帧栈不够用了,如果出现了这种情况,需要了解什么地方创建了很多线程,线上程序需要用jstack命令,将当前线程的状态导出来放到文件里边,然后将文件上传到fastthread.io网站上进行分析。

0x03:看一下栈溢出的另一种情况,这就是栈的StackOverFlow的情况。下面就是一个死循环递归调用。

package oom;/** * @Date 2020-07-18 */public class StackOFE {    public static void stackOverFlowErrorMethod() {        stackOverFlowErrorMethod();    }    public static void main(String[] args) {        stackOverFlowErrorMethod();    }}

运行之后出现的错误如下,程序每次递归的时候,程序会把数据结果压入栈,包括里边的指针等,这个时候就需要帧栈大一些才能承受住更多的递归调用。通过-Xss进行设置,上边的例子需要设置小一些,以分配更多的帧栈,这次是一个帧栈需要记录程序数据,所以需要更大的值。

/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -Xss2mException in thread "main" java.lang.StackOverflowError    at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10)    at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10)    at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10)    at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10)    at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10)    at oom.StackOFE.stackOverFlowErrorMethod(StackOFE.java:10)

遇到上面的情况下,那么就需要通过jstack将线程数据导到文件进行分析。找到递归的点,如果程序就是需要递归的次数的话,那么这个时候就需要增大帧栈的大小以适应程序。

0x04: 元数据区域溢出,元数据区域也成为方法区,存储着类的相关信息,常量池,方法描述符,字段描述符,运行时产生大量的类就会造成这个区域的溢出。我们运行的时候指定一下元数据区域的大小,设置到idea的VM options里边:-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=30M。

package oom;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** * @Date 2020-07-18 */public class MetaspaceOOM {    static class OOMObject{}    public static void main(String[] args) {        while (true) {            Enhancer enhancer = new Enhancer();            enhancer.setSuperclass(OOMObject.class);            enhancer.setUseCache(false);            enhancer.setCallback(new MethodInterceptor() {                public Object intercept(Object obj, Method method,                                        Object[] args, MethodProxy proxy) throws Throwable {                    return proxy.invokeSuper(obj, args);                }            });            enhancer.create();        }    }}

运行的结果如下,元数据信息溢出了。这种情况产生的原因有:通过CBLIG大量生成类,导致Meta信息满了;JDK7的时候使用String.intern()不当,会产生大量常量数据;加载大量的jsp以及动态生成jsp文件。需要调整元数据空间的大小,如果调大了之后还出现了这种异常,我们需要分析哪里出现的溢出并fix掉。

/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -XX:MetaspaceSizeException in thread "main" java.lang.OutOfMemoryError: Metaspace    at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:345)    at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)    at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:114)    at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)    at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)    at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305)    at oom.MetaspaceOOM.main(MetaspaceOOM.java:28)Process finished with exit code 1

0x05: 直接内存溢出,除了使用堆内存外,还可能用直接内存,即堆外内存。NIO为了提高性能,避免在Java Heap和native Heap中切换,所以使用直接内存,默认情况下,直接内存的大小和对内存大小一致。堆外内存不受JVM的限制,但是受制于机器整体内存的大小限制。如下代码设置堆最大内存为128m,直接内存为100m,然后我们每次分配1M放到list里边。  

-Xmx128m -XX:MaxDirectMemorySize=100Mpackage oom;import java.nio.ByteBuffer;import java.util.ArrayList;import java.util.List;/** * @Date 2020-07-18 */public class DirectBufferOOM {    public static void main(String[] args) {        final int _1M = 1024 * 1024 * 1;        List buffers = new ArrayList<>();        int count = 1;        while (true) {            ByteBuffer byteBuffer = ByteBuffer.allocateDirect(_1M);            buffers.add(byteBuffer);            System.out.println(count++);        }    }}

这个时候,当输出100次的时候,下次再分配的时候会报OOM-Direct buffer memory。

/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/bin/java -Xmx128m Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory    at java.nio.Bits.reserveMemory(Bits.java:694)    at java.nio.DirectByteBuffer.(DirectByteBuffer.java:123)    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)    at oom.DirectBufferOOM.main(DirectBufferOOM.java:18)Process finished with exit code 1

这种情况是我们使用直接内存造成溢出,这个时候我们需要检查一下程序里边是否使用的NIO及NIO,比如Netty,里边的直接内存的配置。

0x06: JDK1.6之后新增了一个错误类型,如果堆内存太小的时候会报这个错误。如果98%的GC的时候回收不到2%的时候会报这个错误,也就是最小最大内存出现了问题的时候会报这个错误。如果代码配置了最小最大堆内存都为10m。

-Xmx10m -Xms10mpackage oom;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/** * @Date 2020-07-18 */public class GCOverheadOOM {    public static void main(String[] args) {        ExecutorService executor = Executors.newFixedThreadPool(5);        for (int i = 0; i  {                try {                    Thread.sleep(10000);                } catch (InterruptedException e) {                    //do nothing                }            });        }    }}

这个创建了一个线程池,如果线程池执行的时候如果核心线程处理不过来的时候会把数据放到LinkedBlockingQueue里边,也就是堆内存当中。这个时候我们需要检查-Xms -Xmx最小最大堆配置是否合理。再一个dump出现当前内存来分析一下是否使用了大量的循环或使用大量内存代码。

以上就是经常遇到的情况,需要针对出现的不同情况进行分析和处理。

idea内存溢出解决_各种OOM代码样例及解决方法相关推荐

  1. 各种OOM代码样例及解决方法

    点击上方「蓝字」关注我们 针对目前大家对OOM的类型不太熟悉,那么来总结一下各种OOM出现的情况以及解决方法.把各种OOM的情况列出来,然后逐一进行代码编写复现和提供解决方法. 1. 堆溢出-java ...

  2. jvm性能调优实战 -54Jetty NIO机制导致堆外内存溢出Direct buffer memory OOM

    文章目录 Pre 案例 故障分析 关于解决OOM问题的底层技术修为的一点建议 堆外内存是如何申请的,又是如何释放的? 为什么会出现堆外内存溢出的情况? 真正的堆外内存溢出原因分析 Java NIO有这 ...

  3. 内存溢出案例_「性能优化」纳尼?内存又溢出了?是时候总结一波了

    写在前面 相信小伙伴们在平时工作的过程中,或多或少都会遇到一个场景:内存溢出.如果你没有遇到过这个场景,那就说明你是个假的程序员.哈哈,开个玩笑,平时工作过程中,我们确实会遇到这个问题.今天,我就将平 ...

  4. pytorch geometric GraphSAGE代码样例reddit和ogbn_products_sage,为何subgraph_loader将sizes设成[-1]

    pytorch geometric GraphSAGE代码样例reddit和ogbn_products_sage,为何subgraph_loader将sizes设成[-1] loader infere ...

  5. Android拍照上传代码样例

    2019独角兽企业重金招聘Python工程师标准>>> Android拍照上传代码样例 1.LoginWindow.java --登录窗口 package com.hemi.rhet ...

  6. java二重循环计数_java的二重循环代码样例

    1.计算三个班的平均分 import java.util.Scanner; public class AvgScore{ public static void main (Sting[] args){ ...

  7. python开发接口故障码_Python代码样例

    Python代码样例 链接复制成功! 分享 微博 分享文档到微博 微信 扫码分享文档 复制链接 复制链接到剪贴板 更新时间:2020/10/27 GMT+08:00 Python代码样例如下所示: & ...

  8. linux 内存溢出排查_记一次JAVA 线上故障排查完整套路

    JAVA线上故障排查全套路 线上故障主要会包括cpu.磁盘.内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以进行排查时候尽量四个方面依次排查一遍.同时例如jstack.jmap等工具也 ...

  9. linux 内存溢出排查_【开发者成长】JAVA 线上故障排查完整套路!

    云栖号资讯:[点击查看更多行业资讯] 在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 线上故障主要会包括 CPU.磁盘.内存以及网络问题,而大多数故障可能会包含不止一个层面的问题,所以 ...

最新文章

  1. 时间立即同步命令_Redis复制:主从同步
  2. PHP获取用户ip、地理位置、浏览器和系统信息
  3. mysql数据聚合技术_Mysql 去重 聚合
  4. 计算机网络对口题目,2011-2015计算机对口升学网络试题汇总.doc
  5. C语言-获取当前时间-格式化输出(完整代码)
  6. promise的状态值_ES6中的Promise的用法总结
  7. (网页)JS实现alert中显示换行的方法
  8. NHibernet能带来什么呢?
  9. numpy flatten
  10. 这就是XcodeGhost作者的原话
  11. 信捷plc485通信上位机_变频器、触摸屏和PLC建立MODBUS RTU通信的方法
  12. 《系统集成项目管理》第八章 项目进度管理
  13. 电阻式触摸屏和电容式触摸屏区别
  14. 偶极子天线的优缺点_一种双面印刷偶极子天线解析
  15. VS Code(8)- 终端模拟器
  16. WordPress整合ckplayer X3视频播放器插件
  17. AutoHotKey方向键组合
  18. 消费者和生产者问题,管程法和信号灯法
  19. 基于JavaScript的幸运大转盘
  20. 关闭HttpClient

热门文章

  1. Springboot2 Quartz实现JAVA定时任务的动态配置
  2. 解决 idea 运行 Spring Boot 项目启动慢的问题
  3. 查看linux系统版本信息(Oracle Linux、Centos Linux、Redhat Linux、Debian、Ubuntu)
  4. Centos7 使用Docker 部署Tomca+mysql+调试联通_02
  5. 使用html2Canvas将页面转化为canvas图片,最后长按保存到本地,史上最全 html2canvas 使用 踏坑之旅,没有之一
  6. 微信小程序---实现弹窗效果
  7. qt中QMap与QMultimap用foreach遍历
  8. qt使用动画提示正在载中
  9. 服务器修改用户组权限设置,如何:修改用户的权限
  10. php 图片印章_php工具型代码之印章抠图