美文网首页
内存异常的那些事(一)

内存异常的那些事(一)

作者: 勤_ | 来源:发表于2021-07-20 16:20 被阅读0次

概述

接着上篇性能调优(三),通过一些实例继续分析性能问题的现象和原因,希望能给研发兄弟们一点点参考价值。

工具及版本

工具 版本
Arthas 3.5.2
perf 3.10.0-1160.31.1.el7.x86_64.debug
JDK 1.8.0_221

实例

根据 JVM8 规范,JVM 运行时内存共分为虚拟机栈、堆、元空间、程序计数器、本地方法栈五个部分。还有一部分内存叫直接内存,属于操作系统的本地内存,也是可以直接操作的。接下来通过代码来演示下内存溢出的一些异常。

11.png

堆溢出

  • 编写以下代码验证

    /**
       * -Xmx32M -Xms32M
       * */
      @GetMapping("/heapOom")
      public String heapOomErr() {
          List<byte[]> list = new ArrayList<>();
          while(true){
              list.add(new byte[8*1024*1024]);
          }
      }
    
  • 启动虚拟机的时候配置-Xmx32M -Xms32M,触发溢出的代码,一会后报错如下:

    java.lang.OutOfMemoryError: Java heap space
      at com.lqd.jvm.monitor.MemoryController.heapOomErr(MemoryController.java:24) ~[classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_251]
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_251]
      at 
    
  • 解决方案:在保证没有内存泄漏的情况下,一般可以适当调整-Xmx -Xms。

元空间溢出

  • 编写以下代码

    /**
       * -XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M
       * */
      @GetMapping("/nonheap")
      public String nonheap() {
          while(true) {
              classList.addAll(Metaspace.createClasses());
          }
      }
    
  • 启动虚拟机的时候配置 -XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M,触发溢出的代码,一会后报错如下:

    java.lang.OutOfMemoryError: Metaspace
      at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_251]
      at java.lang.ClassLoader.defineClass(ClassLoader.java:756) ~[na:1.8.0_251]
      at java.lang.ClassLoader.defineClass(ClassLoader.java:635) ~[na:1.8.0_251]
      at com.lqd.jvm.monitor.Metaspace.createClasses(Metaspace.java:39) ~[classes/:na]
      at com.lqd.jvm.monitor.MemoryController.nonheap(MemoryController.java:48) ~[classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_251]
      at 
    
  • 解决方案:在保证没有内存泄漏的情况下,一般可以适当调整-XX:MetaspaceSize -XX:MaxMetaspaceSize。

垃圾回收超时

  • 代码不变,这时设置-Xmx32M -Xms32M,触发/nonheap消耗元空间的内存空间,一会后报错如下,这是因为经过多次长时间的GC操作都无法回收,导致可用内存越来越少。JVM花费了98%的时间进行垃圾回收,而只得到2%可用的内存,频繁的进行内存回收(最起码已经进行了5次连续的垃圾回收),JVM就会曝出java.lang.OutOfMemoryError: GC overhead limit exceeded错误。

    java.lang.OutOfMemoryError: GC overhead limit exceeded
      at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_251]
      at java.lang.ClassLoader.defineClass(ClassLoader.java:756) ~[na:1.8.0_251]
      at java.lang.ClassLoader.defineClass(ClassLoader.java:635) ~[na:1.8.0_251]
      at com.lqd.jvm.monitor.Metaspace.createClasses(Metaspace.java:39) ~[classes/:na]
      at com.lqd.jvm.monitor.MemoryController.nonheap(MemoryController.java:48) ~[classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_251]
    
  • 解决方案:检测代码干掉内存泄漏的代码。

栈溢出

  • 编写以下代码

    /**
       * -Xss
       * */
      @GetMapping("/stackOom")
      public void stackOom() {
          int num =1 ;
          testStack();
      }
    
      private void testStack(){
          int i = 2,temp = 0;
          i = temp;
          temp = 2;
          this.testStack();
      }
    
  • 启动虚拟机的时候配置-Xss128k,触发溢出的代码,一会后报错如下:

    java.lang.StackOverflowError: null
      at com.lqd.jvm.monitor.MemoryController.testStack(MemoryController.java:57) ~[classes/:na]
      at com.lqd.jvm.monitor.MemoryController.testStack(MemoryController.java:57) ~[classes/:na]
      at com.lqd.jvm.monitor.MemoryController.testStack(MemoryController.java:57) ~[classes/:na]
      at com.lqd.jvm.monitor.MemoryController.testStack(MemoryController.java:57) ~[classes/:na]
      at com.lqd.jvm.monitor.MemoryController.testStack(MemoryController.java:57) ~[classes/:na]
    
  • 解决方案:在保证没有内存泄漏的情况下,一般可以适当调整-Xss。

直接内存溢出

  • 编写以下代码

    /**
       * -XX:MaxDirectMemorySize
       * */
      @GetMapping("/directOom")
      public void directOom() {
          try {
              int i = 0 ;
              Field field = Unsafe.class.getDeclaredField("theUnsafe");
              field.setAccessible(true);
              Unsafe unsafe = (Unsafe) field.get(null);
              while(true){
                  i++ ;
                  unsafe.allocateMemory(1024 * 1024) ;
              }
          } catch (NoSuchFieldException e) {
              e.printStackTrace();
          } catch (IllegalAccessException e) {
              e.printStackTrace();
          }
      }
    
  • 启动虚拟机,触发溢出的代码,一会后报错如下:

    java.lang.OutOfMemoryError: null
      at sun.misc.Unsafe.allocateMemory(Native Method) ~[na:1.8.0_251]
      at com.lqd.jvm.monitor.MemoryController.directOom(MemoryController.java:66) ~[classes/:na]
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_251]
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_251]
      at 
      
      #
    # There is insufficient memory for the Java Runtime Environment to continue.
    # Native memory allocation (malloc) failed to allocate 32744 bytes for ChunkPool::allocate
    # An error report file with more information is saved as:
    
  • 解决方案:在保证没有内存泄漏的情况下,一般可以适当调整-XX:MaxDirectMemorySize。

参考

cpu高的怎么回事(一)

cpu高的怎么回事(二)

cpu高的怎么回事(三)

Arthas 安装

pidstat

相关文章

  • 内存异常的那些事(一)

    概述 接着上篇性能调优(三)[https://www.jianshu.com/p/7730e9d23d32],通过...

  • JVM内存的那些事

    简书 占小狼转载请注明原创出处,谢谢! 前言 对于C语言开发的程序员来说,在内存管理方面,必须负责每一个对象的生命...

  • OC内存管理

    内存管理的方式 为什么要管理内存 内存问题体现在两个-----内存溢出、野指针异常。 内部溢出 野指针异常 内存管...

  • 内存分页、寻址方式那些事

    内存管理、寻址方式那些事 一、内存 1.1 什么是内存 简单地说,内存就是一个数据货架。内存有一个最小的存储单位,...

  • 内存缓存那些事

    内存缓存 缓存分为2类,内存缓存和磁盘缓存,今天说的是内存缓存。 内存缓存实现很多种方式,最简单的是就是用NSMu...

  • 内存泄露那些事

    在JavaScript中,由于编码者忽略或者不注意某些细节,经常会造成内存泄露。 首先,什么是内存泄漏?这是个什么...

  • 【JVM】内存溢出分析

    一 内存溢出概述 都有发生内存溢出异常(OutOfMemoryError,简称OOM)的可能。 内存溢出和内存泄漏...

  • php异常处理的那些事

    先上代码: 总结: 1.在php中我们平常用的try,catch只能捕获我们主动抛出的异常,当然除非你的框架已经帮...

  • 那些旅行告诉我们的事

    那些旅行告诉我们的事 网络异常取消重新上传 网络异常取消重新上传 网络异常取消重新上传 网络异常取消重新上传 网络...

  • Java内存区域与内存异常异常

    运行时数据区 方法区(Method Area) 存放已加载的信息 异常 如果无法满足内存分配时抛出OutOfMem...

网友评论

      本文标题:内存异常的那些事(一)

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