美文网首页
如何快速制造OOM

如何快速制造OOM

作者: 站在海边看远方 | 来源:发表于2020-09-24 18:43 被阅读0次

    为了验证JVM发生OOM时自动保存dump的参数配置是否正确,需要验证一下,所以有了这次的验证过程。

    OOM

    OOM是OutOfMemory的缩写,内存溢出,Java中的OOM是在java.lang.OutOfMemoryError类中定义的,类注释如下:

    Thrown when the Java Virtual Machine cannot allocate an obje because it is out of memory, and no more memory could be made
      available by the garbage collector.
    

    发生OOM是因为没有可用内存进行分配了,所以抛出错误,错误代表虚拟机无法自我恢复,需要外力介入。

    Java中的OOM有几下几种常见的类型:

    1. java.lang.OutOfMemoryError: Java heap space
      堆空间不够了,抛出了OOM异常。

    2. java.lang.OutOfMemoryError: PermGen space/ Metaspace
      永久代/元空间溢出了,Java8使用Metaspace取代了PermGen。
      Java永久代(元数据)溢出,即方法区溢出了,一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。

    3. java.lang.OutOfMemoryError: unable to create new native thread
      Linux系统默认一个进程可以创建最多1024个线程,创建的线程数量太多超过了系统的限制,抛出了这个异常。

    4. java.lang.OutOfMemoryError:GC overhead limit exceeded
      在并行或者并发回收器在GC回收时间过长、超过98%的时间用来做GC并且回收了不到2%的堆内存,然后抛出这种异常进行提前预警,用来避免内存过小造成应用不能正常工作

    5. java.lang.OutMemoryError:Direct buffer memory

    写NIO程序使用ByteBuffer来读取或者写入数据,这是基于通道(channel)和缓冲区(buffer)的IO方式,可以使用Native函数库直接分配堆内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作,这样在一些场景中能够提高性能,避免了Java堆和native堆中来回复制数据。

    还有2种和OOM有关系的异常:

    1. java.lang.StackOverflowError
      是JVM的线程由于递归或者方法调用层次太多,占满了线程堆栈而导致的,线程堆栈默认大小为1M。

    2. java.net.SocketException: Too many open files
      是由于系统对文件句柄的使用是有限制的,而某个应用程序使用的文件句柄超过了这个限制,就会导致这个问题

    模拟过程

    介绍了一下常见的OOM,我们采用最简单的Java heap space进行模拟,将堆内存设置的小一点,然后循环创建对象。

    JVM参数设置:

     -Xms8m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="E:\heapdump.hprof"
    

    然后使用while循环创建对象

    public class HeapSpaceOomTest {
        public static void main(String[] args) {
            ArrayList<Object> list = new ArrayList<>(100000);
            while (true) {
                list.add(new Object());
            }
        }
    }
    

    运行结果如下,可以看到按照预期抛出了OOM异常,然后生成了dump文件

    java.lang.OutOfMemoryError: Java heap space
    Dumping heap to E:\heapdump.hprof ...
    Heap dump file created [9849369 bytes in 0.030 secs]
    Exception 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:265)
        at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
        at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
        at java.util.ArrayList.add(ArrayList.java:462)
        at com.fc.oom.HeapSpaceOomTest.main(HeapSpaceOomTest.java:15)
    
    Process finished with exit code 1
    

    将生成的dump文件使用工具进行分析,这里推荐一个在线产品,
    https://console.perfma.com/

    这是前阿里的JVM大佬寒泉子创办的公司,他们提供了免费的社区产品,有虚拟机参数分析工具、线程dump分析工具、堆dump分析3款产品,分析效果还不错,以图表形式提供,并且有多个维度的分析报告

    image.png

    由于堆空间太小,所以对象占用空间不大,线程之类的比较大。

    下面是分析结果的地址:
    https://memory.share.perfma.com/detail/1900154

    小结

    JDK1.7常常会发生永久代的OOM,1.8使用元空间替换永久代之后这种情况就少了不少,了解常见的OOM,以及如何保存OOM dump对分析故障会有一些帮助。

    参考文章

    https://www.jianshu.com/p/4645254be259
    https://www.jianshu.com/p/0744abda44cb
    https://www.cnblogs.com/shemlo/p/11665917.html

    相关文章

      网友评论

          本文标题:如何快速制造OOM

          本文链接:https://www.haomeiwen.com/subject/ufzzyktx.html