一、JVM中常见的两种错误

StackoverFlowError

  • java.lang.StackOverflowError

OutofMemoryError

  • java.lang.OutOfMemoryError:java heap space
  • java.lang.OutOfMemoryError:GC overhead limit exceeeded
  • java.lang.OutOfMemoryError:Direct buffer memory
  • java.lang.OutOfMemoryError:unable to create new native thread
  • java.lang.OutOfMemoryError:Metaspace

二、案例

2.1 StackOverflowError

栈内存溢出。

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

输出结果:

Exception in thread “main” java.lang.StackOverflowError
at com.lun.jvm.StackOverflowErrorDemo.main(StackOverflowErrorDemo.java:6)
at com.lun.jvm.StackOverflowErrorDemo.main(StackOverflowErrorDemo.java:6)
at com.lun.jvm.StackOverflowErrorDemo.main(StackOverflowErrorDemo.java:6)

2.2 OOM之Java heap space

堆内存溢出。

public class OOMEJavaHeapSpaceDemo {/*** * -Xms10m -Xmx10m* * @param args*/public static void main(String[] args) {byte[] array = new byte[80 * 1024 * 1024];}}

输出结果:

Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
at com.lun.jvm.OOMEJavaHeapSpaceDemo.main(OOMEJavaHeapSpaceDemo.java:6)

2.3 OOM之GC overhead limit exceeded

GC overhead limit exceeded:超出GC开销限制

GC回收时间过长时会抛出OutOfMemroyError。时间过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存,连续多次GC 都只回收了不到2%的极端情况下才会抛出。

假如不抛出GC overhead limit错误会发生什么情况呢?那就是GC清理的这么点内存很快会再次填满,迫使cc再次执行。这样就形成恶性循环,CPU使用率一直是100%,而Gc却没有任何成果。

import java.util.ArrayList;
import java.util.List;public class OOMEGCOverheadLimitExceededDemo {/*** * -Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m* * @param args*/public static void main(String[] args) {int i = 0;List<String> list = new ArrayList<>();try {while(true) {list.add(String.valueOf(++i).intern());}} catch (Exception e) {System.out.println("***************i:" + i);e.printStackTrace();throw e;}}}

输出结果

[GC (Allocation Failure) [PSYoungGen: 2048K->498K(2560K)] 2048K->1658K(9728K), 0.0033090 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2323K->489K(2560K)] 3483K->3305K(9728K), 0.0020911 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2537K->496K(2560K)] 5353K->4864K(9728K), 0.0025591 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [PSYoungGen: 2410K->512K(2560K)] 6779K->6872K(9728K), 0.0058689 secs] [Times: user=0.09 sys=0.00, real=0.01 secs]
[Full GC (Ergonomics) [PSYoungGen: 512K->0K(2560K)] [ParOldGen: 6360K->6694K(7168K)] 6872K->6694K(9728K), [Metaspace: 2651K->2651K(1056768K)], 0.0894928 secs] [Times: user=0.42 sys=0.00, real=0.09 secs]
[Full GC (Ergonomics) [PSYoungGen: 2048K->1421K(2560K)] [ParOldGen: 6694K->6902K(7168K)] 8742K->8324K(9728K), [Metaspace: 2651K->2651K(1056768K)], 0.0514932 secs] [Times: user=0.34 sys=0.00, real=0.05 secs]
[Full GC (Ergonomics) [PSYoungGen: 2048K->2047K(2560K)] [ParOldGen: 6902K->6902K(7168K)] 8950K->8950K(9728K), [Metaspace: 2651K->2651K(1056768K)], 0.0381615 secs] [Times: user=0.13 sys=0.00, real=0.04 secs]
…省略89行…
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7044K->7044K(7168K)] 9092K->9092K(9728K), [Metaspace: 2651K->2651K(1056768K)], 0.0360935 secs] [Times: user=0.25 sys=0.00, real=0.04 secs]
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7046K->7046K(7168K)] 9094K->9094K(9728K), [Metaspace: 2651K->2651K(1056768K)], 0.0360458 secs] [Times: user=0.38 sys=0.00, real=0.04 secs]
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7048K->7048K(7168K)] 9096K->9096K(9728K), [Metaspace: 2651K->2651K(1056768K)], 0.0353033 secs] [Times: user=0.11 sys=0.00, real=0.04 secs]
***************i:147041
[Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7050K->7048K(7168K)] 9098K->9096K(9728K), [Metaspace: 2670K->2670K(1056768K)], 0.0371397 secs] [Times: user=0.22 sys=0.00, real=0.04 secs]
java.lang.OutOfMemoryError: GC overhead limit exceeded
[Full GC (Ergonomics) at java.lang.Integer.toString(Integer.java:401)
[PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7051K->7050K(7168K)] 9099K->9097K(9728K), [Metaspace: 2676K->2676K(1056768K)], 0.0434184 secs] [Times: user=0.38 sys=0.00, real=0.04 secs]
at java.lang.String.valueOf(String.java:3099)
at com.lun.jvm.OOMEGCOverheadLimitExceededDemo.main(OOMEGCOverheadLimitExceededDemo.java:19)
Exception in thread “main” java.lang.OutOfMemoryError: GC overhead limit exceeded
[Full GC (Ergonomics) [PSYoungGen: 2047K->0K(2560K)] [ParOldGen: 7054K->513K(7168K)] 9102K->513K(9728K), [Metaspace: 2677K->2677K(1056768K)], 0.0056578 secs] [Times: user=0.11 sys=0.00, real=0.01 secs]
at java.lang.Integer.toString(Integer.java:401)
at java.lang.String.valueOf(String.java:3099)
at com.lun.jvm.OOMEGCOverheadLimitExceededDemo.main(OOMEGCOverheadLimitExceededDemo.java:19)
Heap
PSYoungGen total 2560K, used 46K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
eden space 2048K, 2% used [0x00000000ffd00000,0x00000000ffd0bb90,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
to space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
ParOldGen total 7168K, used 513K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
object space 7168K, 7% used [0x00000000ff600000,0x00000000ff6807f0,0x00000000ffd00000)
Metaspace used 2683K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 285K, capacity 386K, committed 512K, reserved 1048576K

由代码可见,while循环不停的将堆内存填满,GC不停的回收,进入恶性循环,于是抛出了这个错误:java.lang.OutOfMemoryError: GC overhead limit exceeded

2.4 OOM之Direct buffer memory

导致原因:

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

  • ByteBuffer.allocate(capability)
    第一种方式是分配VM堆内存,属于GC管辖范围,由于需要拷贝所以速度相对较慢。
  • ByteBuffer.allocateDirect(capability)
    第二种方式是分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快。

但如果不断分配本地内存,堆内存很少使用,那么JV就不需要执行GC,DirectByteBuffer对象们就不会被回收,这时候堆内存充足,但本地内存可能已经使用光了,再次尝试分配本地内存就会出现OutOfMemoryError,那程序就直接崩溃了。

import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;public class OOMEDirectBufferMemoryDemo {/*** -Xms5m -Xmx5m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m* * @param args* @throws InterruptedException*/public static void main(String[] args) throws InterruptedException {System.out.println(String.format("配置的maxDirectMemory: %.2f MB",// sun.misc.VM.maxDirectMemory() / 1024.0 / 1024));TimeUnit.SECONDS.sleep(3);ByteBuffer bb = ByteBuffer.allocateDirect(6 * 1024 * 1024);}
}

输出结果:

[GC (Allocation Failure) [PSYoungGen: 1024K->504K(1536K)] 1024K->772K(5632K), 0.0014568 secs] [Times: user=0.09 sys=0.00, real=0.00 secs]
配置的maxDirectMemory: 5.00 MB
[GC (System.gc()) [PSYoungGen: 622K->504K(1536K)] 890K->820K(5632K), 0.0009753 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 504K->0K(1536K)] [ParOldGen: 316K->725K(4096K)] 820K->725K(5632K), [Metaspace: 3477K->3477K(1056768K)], 0.0072268 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
Exception in thread “main” Heap
PSYoungGen total 1536K, used 40K [0x00000000ffe00000, 0x0000000100000000, 0x0000000100000000)
eden space 1024K, 4% used [0x00000000ffe00000,0x00000000ffe0a3e0,0x00000000fff00000)
from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
to space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
ParOldGen total 4096K, used 725K [0x00000000ffa00000, 0x00000000ffe00000, 0x00000000ffe00000)
object space 4096K, 17% used [0x00000000ffa00000,0x00000000ffab5660,0x00000000ffe00000)
Metaspace used 3508K, capacity 4566K, committed 4864K, reserved 1056768K
class space used 391K, capacity 394K, committed 512K, reserved 1048576K
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 com.lun.jvm.OOMEDirectBufferMemoryDemo.main(OOMEDirectBufferMemoryDemo.java:20)

2.5 OOM之unable to create new native thread故障演示

不能够创建更多的新的线程了,也就是说创建线程的上限达到了

高并发请求服务器时,经常会出现异常java.lang.OutOfMemoryError:unable to create new native thread,准确说该native thread异常与对应的平台有关

导致原因:

  • 应用创建了太多线程,一个应用进程创建多个线程,超过系统承载极限
  • 服务器并不允许你的应用程序创建这么多线程,linux系统默认运行单个进程可以创建的线程为1024个,如果应用创建超过这个数量,就会报
    java.lang.OutOfMemoryError:unable to create new native thread

解决方法:

  • 想办法降低你应用程序创建线程的数量,分析应用是否真的需要创建这么多线程,如果不是,改代码将线程数降到最低
  • 对于有的应用,确实需要创建很多线程,远超过linux系统默认1024个线程限制,可以通过修改Linux服务器配置,扩大linux默认限制
public class OOMEUnableCreateNewThreadDemo {public static void main(String[] args) {for (int i = 0; ; i++) {System.out.println("************** i = " + i);new Thread(() -> {try {TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);} catch (InterruptedException e) {e.printStackTrace();}}, String.valueOf(i)).start();}}
}

上面程序在Linux OS(CentOS)运行,会出现下列的错误,线程数大概在900多个

Exception in thread “main” java.lang.OutOfMemoryError: unable to cerate new native thread

OOM之unable to create new native thread上限调整

非root用户登录Linux系统(CentOS)测试

服务器级别调参调优

查看系统线程限制数目

ulimit -u

修改系统线程限制数目

vim /etc/security/limits.d/90-nproc.conf

打开后发现除了root,其他账户都限制在1024个


假如我们想要张三这个用卢运行,希望他生成的线程多一些,我们可以如下配置

2.6 OOM之Metaspace

使用java -XX:+PrintFlagsInitial命令查看本机的初始化参数,-XX:MetaspaceSize为21810376B(大约20.8M)

Java 8及之后的版本使用Metaspace来替代永久代。

Metaspace是方法区在Hotspot 中的实现,它与持久代最大的区别在于:Metaspace并不在虚拟机内存中而是使用本地内存也即在Java8中, classe metadata(the virtual machines internal presentation of Java class),被存储在叫做Metaspace native memory。

永久代(Java8后被原空向Metaspace取代了)存放了以下信息:

  • 虚拟机加载的类信息
  • 常量池
  • 静态变量
  • 即时编译后的代码

模拟Metaspace空间溢出,我们借助CGLib直接操作字节码运行时不断生成类往元空间灌,类占据的空间总是会超过Metaspace指定的空间大小的。

首先添加CGLib依赖

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.10</version>
</dependency>
import java.lang.reflect.Method;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;public class OOMEMetaspaceDemo {// 静态类static class OOMObject {}/*** -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m* * @param args*/public static void main(final String[] args) {// 模拟计数多少次以后发生异常int i =0;try {while (true) {i++;// 使用Spring的动态字节码技术Enhancer enhancer = new Enhancer();enhancer.setSuperclass(OOMObject.class);enhancer.setUseCache(false);enhancer.setCallback(new MethodInterceptor() {@Overridepublic 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("发生异常的次数:" + i);e.printStackTrace();} finally {}}
}

输出结果
发生异常的次数:569

java.lang.OutOfMemoryError: Metaspace
at net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:348)
at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)
at net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:117)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305)
at com.lun.jvm.OOMEMetaspaceDemo.main(OOMEMetaspaceDemo.java:37)

JVM-常见SOFE和OOM错误(十)相关推荐

  1. Java常见内存溢出(OOM)解决方案

    Java 常见内存溢出(OOM)解决方案 一,jvm内存区域   1,         程序计数器 一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器. 2,         java栈 与 ...

  2. mysql 错误问题_Mysql常见的几个错误问题及解决方法:

    Mysql常见的几个错误问题及解决方法: 1.问题: mysql DNS反解:skip-name-resolve 错误日志有类似警告: 点击(此处)折叠或打开 120119 16:26:04 [War ...

  3. golang-文章翻译-go常见的10种错误

    文章目录 一.枚举默认值和json反序列化 二.BenchMarking和内联 三.每次传参都应该用指针吗? 四.break和条件控制语句 五.错误管理 六.数组初始化 6.1 len 和 cap 6 ...

  4. JVM:JVM常见参数配置

    JVM常见参数配置 JVM的参数类型: 1.标配参数:-version,-help,-showversion 2.x参数(了解):-Xint:解释执行:-Xcomp:第一次使用就编译成本地代码:-Xm ...

  5. C语言/C++常见习题问答集锦(五十二) 之职工信息管理系统

    C语言/C++常见习题问答集锦(五十二) 之职工信息管理系统 程序之美 用C语言,职工信息管理系统具体要求 1.基本信息:如工号.姓名.性别.年龄.学历.住址.电话号码.工资等. 2.各职工信息用结构 ...

  6. 哪些科幻电影里有计算机知识的常识性错误,盘点科幻电影中最常见的常识性科学错误,原来你被骗了!...

    原标题:盘点科幻电影中最常见的常识性科学错误,原来你被骗了! 科幻电影里让人眼花缭乱的高科技总是让人叹为观止,但是我们在欣赏这些科技特效的同时需要知道,里面的很多东西都犯了常识性的科学错误.下面图帮主 ...

  7. 面试两连击:线上JVM GC问题和OOM内存溢出的解决方案,聊聊呗!

    点击上方石杉的架构笔记,右上角选择"设为星标" 每日早8点半,技术文章准时送上 公众号后台回复"学习",获取作者独家秘制精品资料 往期文章 BAT 面试官是如何 ...

  8. java常见面试考点(二十五):CAS是什么

    java常见面试考点 往期文章推荐:   java常见面试考点(二十):Elasticsearch 和 solr 的区别   java常见面试考点(二十一):单点登录   java常见面试考点(二十二 ...

  9. 初学Python,我给你总结了常见的17个错误

    点击"视学算法","置顶"公众号 重磅干货,第一时间送达 来源:开源中国 链接:https://www.oschina.net/question/89964_6 ...

最新文章

  1. 奇异值分解和图像压缩
  2. [计算机]“华为的冬天”——任正非(华为总裁)
  3. web服务器是如何维护,我们如何维护Web客户端和Web服务器之间的会话?
  4. h5新增 history的应用
  5. Cannot find source code based button in SE24 - modification assistant
  6. java ee的小程序_Java EE调度程序
  7. 决心书之学习linux高级运维
  8. 【Android】11.3 屏幕旋转和场景变换过程中GridView的呈现
  9. python中encode()函数的用法
  10. 手写哈希(实现简单的加数、查询)
  11. ubuntu18下查看opencv版本、多版本之间的共存,切换、下载地址
  12. 如何提高数学分析水平(转载)
  13. 学习 MySQL 需要知道的 28 个小技巧
  14. 泰坦尼克号幸存者预测所用函数
  15. windows10虚拟机安装苹果系统
  16. cocos creator麻将教程系列(二)—— 达达麻将的底层通讯express框架与socketio
  17. 汇编c 易语言编程软件,这些汇编用易语言怎么写?
  18. HardSwish和HardSigmoid的关系
  19. Python常用设计模式—创建型模式
  20. 细思恐极,插上 U 盘就开始执行 Python 代码

热门文章

  1. 二极管的主要特性总结
  2. 2023 iapp 防止被逆向工具加固源码
  3. 用esp8266实现远程空调控制(一)
  4. ROS-3DSLAM(15):视觉部分visual estimator 第九节 factor3
  5. 全国计算机一级考试 最新版理论知识汇总
  6. leetcode题解(五)
  7. Tribon COM组件注册
  8. CodeForces 652C Foe Pairs(思维)
  9. 解决控制台总是提示 martian source 问题
  10. [安卓系统导航升级系统,车机升级系统]汽车系统升级更新,诺威达k2201升级包