当前位置: 首页 > news >正文

JVM 之 内存溢出实战【OOM? SOF? 哪些区域会溢出?堆、虚拟机栈、元空间、直接内存溢出时各自的特点?以及什么情况会导致他们溢出?并模拟溢出】

实战:OutOfMemoryError异常

除了程序计数器外,堆、虚拟机栈、元空间、直接内存都有发生OOM的可能
下面我们演示下引起各区域OOM的情况,及观察下其异常表现,进而初步总结各异常时的调优策略

JVM调优实例

  • 堆:-》OOM: Java heap space ->获取堆转储快照-》分析是溢出(调大堆)还是泄漏(优化代码),并解决
  • 虚拟机栈:
    • -》SOF -》根据堆栈信息去解决;
    • -》OOM -> 线程过多 -》调小堆给虚拟机栈留出内存
  • 元空间 -》OOM:Metaspace ->调整代码+调大元空间上限
  • 直接内存 -》OOM,但堆转储文件很小且没异常-》调大直接内存

Java堆溢出

java堆异常一般是由于创建了太多的无法回收的对象,导致超过了堆的最大容量的。

异常处理思路

所以异常处理时的思路是:

  • 1、先拿到异常的堆转储快照。
  • 2、然后根据快照,判断溢出对象是否必要。
    • 如必要,则是内存溢出,看看能不能调大内存,或者调小一些不必要的对象的生命周期腾出一部分空间。
    • 如不必要,则是内存泄漏,通过GC ROOT查看对象的引用链,看看为啥没有回收,并加以解决。

模拟异常

Java堆OOM是常见情况,异常信息中会进一步提示Java heap space
模拟代码

/** * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\IdeaSpeace\jvm * 限制Java堆的大小为20MB,不可扩展(将堆的最大最小值-Xmx-Xms参数设置一样),出现内存溢出异常的时候Dump出当前的内存堆转储快照,制定存储路径 */publicclassHeapOOM{staticclassOOMObject{}publicstaticvoidmain(String[]args){List<OOMObject>list=newArrayList<OOMObject>();while(true){list.add(newOOMObject());}}}

运行结果

java.lang.OutOfMemoryError: Java heap space Dumping heap to D:\IdeaSpeace\jvm\java_pid8584.hprof ... Heap dump file created [27646160 bytes in 0.090 secs]

详细操作步骤

  • 1、通过-XX:+HeapDumpOnOutOfMemoryError拿到堆转储快照。
  • 2、通过jprofiler工具分析堆转储快照,判断内存中导致OOM的对象是否必要?
    • 2.1、不必要 -> 内存泄漏-> 查看对象GC ROOT引用链,进而定位为何无法回收,最终找到泄漏位置加以解决
    • 2.2、必要 -> 内存溢出-> 调整堆大小、修改不合理代码。
      • 2.2.1、调整堆大小:在机器内存允许的范围内,适当调整java虚拟机(-Xmx与-Xms)堆参数
      • 2.2.2、修改不合理代码:检查代码中是否存在长生命周期的对象,不合理的存储结构设计(比如可以用long但是用map存)

虚拟机栈和本地方法栈溢出

  • 1、栈深度过深(栈深度 > 虚拟机的最大深度) -》StackOverflowError异常。

注意:HotSpot虚拟机中不区分虚拟机栈和本地方法栈,所以栈容量只由-Xss设定(-Xoss参数设置本地方法栈大小不发挥作用)

  • 2、创建线程数过多 -》OOM异常。

(创建线程数 * 线程栈内存) > (进程内存(操作系统限制)- 最大堆容量 - 最大方法区容量)

异常处理思路

  • 1、StackOverflowError异常:根据打印出的堆栈信息去定位即可。

在使用默认-Xss参数的情况下,一般而言到达1000~2000的栈深度是完全没有问题的。(具体深度由压入的栈帧大小决定)

  • 2、OOM异常:此时会提示unable to create native thread表示线程数过多,
    • 2.1、线程数异常创建 -》 优化代码,减少不必要的线程创建
    • 2.2、创建的线程均必须 -》 减少最大堆、减少栈容量,来提升创建线程数。

线程数过多引发OOM时,需反向调整堆大小,来给创建线程分配虚拟机栈提供更多可用内存。

异常代码演示

  • 1、栈深度过深,引发SOF异常
    /** * VM Args:-Xss128k (使用-Xss参数减少栈内存容量) */publicclassJavaVMStackSOF{privateintstackLength=1;publicvoidstackLeak(){stackLength++;stackLeak();}publicstaticvoidmain(String[]args)throwsThrowable{JavaVMStackSOFoom=newJavaVMStackSOF();try{oom.stackLeak();}catch(Throwablee){System.out.println("stack length:"+oom.stackLength);throwe;}}}
    运行结果
    stack length:2298 Exception in thread "main" java.lang.StackOverflowError at com.dream.my.faceTest.jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:11) at com.dream.my.faceTest.jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12) at com.dream.my.faceTest.jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12) ……后续异常堆栈信息省略
  • 2、创建线程数过多,耗尽内存,引发 OOM异常:

    重点提示: 如果运行上面这段代码,记得要先保存当前的工作。 因为在Windows平台的Java的线程是映射到操作系统的内核线程上,创建过多线程可能导致操作系统假死。

    /** * VM Args:-Xss2M (这时候不妨设大些,请在32位系统下运行) */publicclassJavaVMStackOOM{privatevoiddontStop(){while(true){}}publicvoidstackLeakByThread(){while(true){Threadthread=newThread(newRunnable(){@Overridepublicvoidrun(){dontStop();}});thread.start();}}publicstaticvoidmain(String[]args)throwsThrowable{JavaVMStackOOMoom=newJavaVMStackOOM();oom.stackLeakByThread();}}
    异常关键信息unable to create new native thread
    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 com.dream.my.faceTest.jvm.JavaVMStackOOM.stackLeakByThread(JavaVMStackOOM.java:22) at com.dream.my.faceTest.jvm.JavaVMStackOOM.main(JavaVMStackOOM.java:28)

元空间溢出

  • 背景:从jdk7起,方法区就被放在堆中
  • 常见问题:使用aop动态生成大量字节码(cglib)导致OOM

异常排查思路

  • 1、定位到java.lang.OutOfMemoryError: Metaspace即是方法区溢出。
  • 2、确定是否使用了不必要的aop
  • 3、如果类都是必要的,调大元空间的值-XX:MaxMetaspaceSize
# 元空间调优参数 -XX:MaxMetaspaceSize //设置元空间最大值,推荐256M~512M,超过后报OOM(-1 为不限制大小) -XX:MetaspaceSize //达到该值后,元空间进行第一次GC(GC后如仍超过,则扩容未原来的1.2倍) -XX:MinMetaspaceFreeRatio //GC后,元空间最小空闲空间比率,不够则扩容 -XX:MaxMetaspaceFreeRatio //GC后,元空间最大空闲空间比率,多了则缩容

异常演示代码(JDK8)

方法区的主要职责是用于存放类型的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。
对于这部分区域的测试,基本的思路是运行时产生大量的类去填满方法区,直到溢出为止。

/** * VM Args:-XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M * 借助CGLib使得方法区出现内存溢出异常 */publicclassJavaMethodAreaOOM{publicstaticvoidmain(String[]args){while(true){Enhancerenhancer=newEnhancer();enhancer.setSuperclass(OOMObject.class);enhancer.setUseCache(false);enhancer.setCallback(newMethodInterceptor(){publicObjectintercept(Objectobj,Methodmethod,Object[]args,MethodProxyproxy)throwsThrowable{returnproxy.invokeSuper(obj,args);}});enhancer.create();}}staticclassOOMObject{}}

运行结果:

Caused by: java.lang.OutOfMemoryError: Metaspace at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:756) at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:554) ... 7 more

本机直接内存溢出

直接内存不在jvm内存模型内,但也是有可能导致OOM.(典型的间接使用就是NIO)

异常定位排查思路

  • 1、出现了OOM异常,但是Heap Dump文件很小,且期中没什么异常信息,此时就该考虑是不是直接内存溢出了。
  • 2、调整直接内存大小-XX:MaxDirectMemorySize 指定直接内存大小(默认与Java堆最大值一致)

异常演示代码

/** * VM Args:-Xmx20M -XX:MaxDirectMemorySize=10M */publicclassDirectMemoryOOM{privatestaticfinalint_1MB=1024*1024;publicstaticvoidmain(String[]args)throwsException{FieldunsafeField=Unsafe.class.getDeclaredFields()[0];unsafeField.setAccessible(true);//分配本机内存Unsafeunsafe=(Unsafe)unsafeField.get(null);while(true){//真正申请分配内存unsafe.allocateMemory(_1MB);}}}

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) at com.dream.my.faceTest.jvm.DirectMemoryOOM.main(DirectMemoryOOM.java:23)
http://www.cnnetsun.cn/news/51772.html

相关文章:

  • 经典算法题详解之统计重复个数(三)
  • 移动应用开发实验室大一上考核
  • 云数据库服务(如AWS RDS)的优势和考虑因素?
  • 【设计模式|第四篇】适配器模式:让不兼容的接口协同工作
  • asgiref终极指南:高效解决Python异步通信难题
  • 医学影像深度学习知识点总结
  • 从零到一:自动化3D建模的免代码解决方案
  • Kali中生成被控端
  • 13、Linux 文本编辑与命令操作实用指南
  • 20、Linux 备份全攻略
  • 22、Debian系统管理与安全保障全解析
  • 32、Debian变体与基于Debian的其他操作系统
  • 50、无线传感器网络部署方案与加密算法研究
  • 51、无线传感器网络部署方案与LEACH协议优化研究
  • 54、垃圾邮件和即时通讯垃圾信息的分类与控制措施
  • 如何通过AutoGPT生成高质量技术博客为GPU算力引流
  • 多目标蜣螂优化算法NSDBO:微电网多目标优化调度的利器
  • 本研究基于分形纤维丛统一场论,构建了黑洞时空的几何模型,揭示了奇点消解、霍金辐射修正及信息守恒的新机制。该模型的优势在于将宏观时空的广义相对论效应与微观量子的分形特性实现了有机融合。
  • 好写作AI语言侦探:你的论文严谨性“隐形把关人”
  • 解放双手!钉钉智能打卡神器完全上手手册
  • DMXAPI全球模型API调用完全指南:从入门到精通
  • 告别“翻墙“烦恼:DMXAPI让Gemini-3-pro-thinking调用快如闪电
  • leetcode 744. Find Smallest Letter Greater Than Target 寻找比目标字母大的最小字母-耗时100%
  • Home Assistant通知系统:3步打造智能家居提醒中心
  • 学Simulink——机器人轨迹跟踪场景实例:基于Simulink的永磁同步电机笛卡尔空间圆弧轨迹跟踪仿真
  • 【毕业设计/课程设计】基于Java的高校学科竞赛平台的设计与实现/源码+论文+PPT+数据
  • java计算机毕业设计摄影爱好者交流平台 基于SpringBoot的影像作品分享与互动社区 摄影圈层社交与作品点评一体化平台
  • “AI 写的论文,参考文献靠谱吗?”—— 虎贲等考 AI 给出答案:所有参考文献均来自知网、维普,全程可查、合规可溯
  • 2025年AI降重工具深度评测:10款零风险智能改写方案(askpaper与aibiiye实测)
  • java计算机毕业设计社团管理系统 高校学生社团数字化运营平台 校园社团协同管理与活动发布系统