Java虚拟机常见内存溢出错误汇总,Java中常见的坑看了可以少走点弯路

   日期:2020-10-19     浏览:89    评论:0    
核心提示:这篇文章主要汇总了Java虚拟机常见的内存溢出错误,警示大家,避免出错,感兴趣的朋友可以了解下一、引言从事java开发的小伙伴在平时的开发工作中,应该会遇见各式各样的异常和错误,在实际工作中积累的异常或者错误越多,趟过的坑越多,就会使我们编码更加的健壮,就会本能地避开很多严重的坑。以下介绍几个Java虚拟机常见内存溢出错误。以此警示,避免生产血案。最新2020整理收集的一些面试题(都整理成文档),有很多干货,包含netty,spring,线程,spring cloud等详细讲解,也有详细的学习规划.

这篇文章主要汇总了Java虚拟机常见的内存溢出错误,警示大家,避免出错,感兴趣的朋友可以了解下

一、引言

从事java开发的小伙伴在平时的开发工作中,应该会遇见各式各样的异常和错误,在实际工作中积累的异常或者错误越多,趟过的坑越多,就会使我们编码更加的健壮,就会本能地避开很多严重的坑。以下介绍几个Java虚拟机常见内存溢出错误。以此警示,避免生产血案。

最新2020整理收集的一些面试题(都整理成文档),有很多干货,包含netty,spring,线程,spring cloud等详细讲解,也有详细的学习规划图,面试题整理等,我感觉在面试这块讲的非常清楚:获取面试资料只需:点击这里领取!!! 暗号:CSDN

二、模拟Java虚拟机常见内存溢出错误

1、内存溢出之栈溢出错误

package com.jayway.oom; 
  

 public class StackOverflowErrorDemo {  
  
 public static void main(String[] args) {  
  stackOverflowError(); 
 } 
  
 private static void stackOverflowError() {  
  stackOverflowError(); 
 } 
  
}
 

2、内存溢出之堆溢出错误

package com.jayway.oom; 
  
import java.util.Random; 
  

 public class JavaHeapSpaceErrorDemo {  
  
 public static void main(String[] args) {  
  String temp = "java"; 
  //不断地在堆中开辟空间,创建对象,撑爆堆内存
  while (true) {  
    temp += temp + new Random().nextInt(111111111) + new Random().nextInt(222222222); 
    temp.intern(); 
  } 
 } 
}

3、内存溢出之GC超过执行限制错误

package com.jayway.oom; 
  
import java.util.ArrayList; 
import java.util.List; 
  
/** 
  • GC超过执行限制错误
  • 虚拟机参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
    • 抛出异常:Exception in thread “main” java.lang.OutOfMemoryError: GC overhead limit exceeded
    • 导致原因:GC回收时间过长会抛出OutOfMemoryError,何为过长,即超过98%的cpu时间用来做GC垃圾回收
  • 但是回收效果甚微,仅仅只有2%的CPU时间用来用户程序的工作,这种状态是很糟糕的,程序在不断地GC
  • 形成恶性循环,CPU的使用率一直是满负荷的,正经活却没有干,这种情况虚拟机只好抛出错误来终止程序的执行
  • 不断地Full GC,事倍功微
  • [Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7167K->7161K(7168K)] 9215K->9209K(9728K), [Metaspace: 3529K->3529K(1056768K)], 0.0291829 secs] [Times: user=0.08 sys=0.02, real=0.03 secs]
 */
 public class GCOverheadErrorDemo {  
  
  public static void main(String[] args) {  
    int i = 0; 
    List<String> list = new ArrayList<>(); 
    try {  
      while (true) {  
      list.add(String.valueOf(++i).intern()); 
      } 
    } catch (Throwable e) {  
      System.out.println("*****************i:" + i); 
      e.printStackTrace(); 
      throw e; 
    } 
  } 
}
 

4、内存溢出之直接内存溢出错误

package com.jayway.oom; 
  
import java.nio.ByteBuffer; 
  
/** 
  • 直接内存溢出错误
  • 抛出异常:Exception in thread “main” java.lang.OutOfMemoryError: Direct buffer memory
    • 配置虚拟机参数:-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
    • 导致原因:通常NIO程序经常使用ByteBuffer来读取或者写入数据,这是一种基于通道(Channel)与缓冲区(Buffer)的IO方式,
  • 它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用,
  • 这样能子一些场景中显著提高性能,因为避免了在Java堆和Native内存中来回复制数据。
  • ByteBuffer.allocate(capability):分配JVM堆内存,数据GC的管辖范围,由于需要拷贝所以速度相对较慢
  • ByteBuffer.allocate(capability):分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝,所以速度相对较快。
  • 但是如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象就不会被回收,此时如果继续分配堆外内存,
  • 可能堆外内存已经被耗光了无法继续分配,此时程序就会抛出OutOfMemoryError,直接崩溃。
 */
 public class DirectBufferMemoryErrorDemo {  
  
  public static void main(String[] args) {  
    //默认JVM配置的最大直接内存是总物理内存的四分之一 
    long maxDirectMemory = sun.misc.VM.maxDirectMemory() / 1024 / 1024; 
    System.out.println("配置的maxDirectMemory:" + maxDirectMemory + "MB"); 
  
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024); 
  } 
  
}
 

5、内存溢出之无法创建新的本地线程

package com.jayway.oom; 
  
/** * 内存溢出之无法创建新的本地线程 * 抛出异常:java.lang.OutOfMemoryError: unable to create new native thread 
    • 描述:
  • 高并发请求服务器时,经常出现java.lang.OutOfMemoryError: unable to create new native thread
  • native thread异常与对应的平台有关
  • 导致原因:
  • 1、应用程序创建了太多线程了,一个应用进程创建的线程数超过系统承载极限。
  • 2、操作系统并不允许你的应用进程创建这么多的线程,linux系统默认允许单个进程可以创建的线程数是1024个
  • 解决方法:
  • 1、想办法降低应用进程创建的线程数量,
  • 2、如果应用程序确实需要这么多线程,超过了linux系统的默认1024个限制,可以通过修改linux服务器配置,提高这个阈值。
 */
 public class UnableCreateNativeThreadErrorDemo {  
  
  public static void main(String[] args) {  
    for (int i = 0; true; i++) {  
      System.out.println("***************i:" + i); 
  
      //不断得创建新线程,直到超过操作系统允许应用进程创建线程的极限 
      new Thread(() -> {  
        try {  
          Thread.sleep(Integer.MAX_VALUE); 
        } catch (InterruptedException e) {  
          e.printStackTrace(); 
        } 
      }).start(); 
    } 
  } 
}

6、内存溢出之元空间溢出错误

package com.jayway.oom; 
  
import org.springframework.cglib.proxy.Enhancer; 
import org.springframework.cglib.proxy.MethodInterceptor; 
import org.springframework.cglib.proxy.MethodProxy; 
  
import java.lang.reflect.Method; 
  
/** 
  • 元空间溢出错误
  • 抛出异常:java.lang.OutOfMemoryError: Metaspace
    • 设置虚拟机参数:-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
    • 描述:Java8及以后的版本使用Metaspace来替代了永久代。metaspace是方法区在HotSpot中的实现,它与持久代最大的区别在于
  • Metaspace并不在虚拟机内存中而是在本地内存中。
  • 元空间存储了以下信息:
  • 1、虚拟机加载的类信息
  • 2、常量池
  • 3、静态变量
  • 4、即时编译后的代码
 */
 public class MetaspaceErrorDemo {  
  
  static class OOMTest {  
  } 
  
  public static void main(String[] args) {  
    int count = 0; 
  
    try {  
    //cglib不断创建类,模拟Metaspace空间溢出,我们不断生成类往元空间中灌,超过元空间大小后就会抛出元空间移除的错误 
      while (true) {  
        count++; 
        Enhancer enhancer = new Enhancer(); 
        enhancer.setSuperclass(OOMTest.class); 
        enhancer.setUseCache(false); 
        enhancer.setCallback(new MethodInterceptor() {  
          @Override
          public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {  
            return methodProxy.invokeSuper(o, args); 
          } 
        }); 
        enhancer.create(); 
      } 
    } catch (Throwable e) {  
      System.out.println("************多少次后发生了异常:" + count); 
      e.printStackTrace(); 
    } 
  } 
}
 

三、总结

以上就是Java虚拟机常见内存溢出错误汇总的详细内容,作为一枚Java程序员真的是太强大了,除了要解决日常的bug还要对付这么多莫名其妙的陷阱,一不小心就掉坑里了。损失的都是自己的头发啊。~~Java中常见的坑还有很多,由于篇幅过长就不一 一展现了。

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服