哪些场景会发生OOM异常

2024-04-27 05:36
文章标签 异常 场景 发生 oom

本文主要是介绍哪些场景会发生OOM异常,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

刚刚开通了一个公众号,会分享一些技术博客和自己觉得比较好的项目,同时会更新一些自己使用的工具和图书资料,后面会整理一些面试资料进行分享,觉得有兴趣的可以关注一下。
在这里插入图片描述

文章目录

  • 前言
  • 1.堆内存溢出
  • 2.栈内存异常
  • 3.直接内存溢出
  • 4. 元空间溢出
  • 5.GC OOM


前言

从今天开始会整理一些常见的面试题目,博客中会涉及一些JVM参数,可以关注一下公众号,回复JVM,即可领取最新版《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》

今天要聊的就是比较经典的OOM问题。主要有5种场景,喜下面分别介绍。


1.堆内存溢出

这是比较常见的一种内存溢出的异常。

堆内存主要用来存储对象实例,我们只要不停的创建对象,并且保证GCROOTS和对象之间有可达路径避免被垃圾回收的话,那么在对象数量超过最大堆的大小限制之后,很快就能出现这个异常。我们可以通过设置堆内存位2M-Xms2m -Xmx2m,然后执行测试代码:

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

异常描述如下:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.base/java.util.Arrays.copyOf(Arrays.java:3512)at java.base/java.util.Arrays.copyOf(Arrays.java:3481)at java.base/java.util.ArrayList.grow(ArrayList.java:237)at java.base/java.util.ArrayList.grow(ArrayList.java:244)at java.base/java.util.ArrayList.add(ArrayList.java:454)at java.base/java.util.ArrayList.add(ArrayList.java:467)at OOM.main(OOM.java:8)

2.栈内存异常

栈是线程私有的,他的生命周期和线程相同,每个方法在执行的同时都会创建一个栈帧,栈帧里面保存了局部变量表、操作数栈、动态链接、方法出口。那方法在调用的过程呢,其实就是栈帧入栈和出栈的过程。
在Java虚拟机规范中对虚拟机栈定义了两种异常。

  • 第一,如果线程请求的栈深度大于虚拟机所允许的深度,就会抛出StackOverflow异常。比如我们可以设置-Xss160k,那其中Xss代表每个线程的栈内存大小,通过测试发现,单线程下无论怎么设置参数,其实都是StackOverflow异常。
public class OOM {private static int length = 1;public static void main(String[] args) {test();}static void test(){System.out.println(length++);test();}
}

结果如下:

15261
Exception in thread "main" java.lang.StackOverflowErrorat java.base/java.io.FileOutputStream.write(FileOutputStream.java:349)at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81)at java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142)at java.base/java.io.PrintStream.write(PrintStream.java:570)at java.base/sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:234)at java.base/sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:313)at java.base/sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:111)at java.base/java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:178)at java.base/java.io.PrintStream.writeln(PrintStream.java:723)at java.base/java.io.PrintStream.println(PrintStream.java:938)at OOM.test(OOM.java:12)at OOM.test(OOM.java:13)
  • 第二种,如果虚拟机栈可以动态扩展的话,并且扩展时无法申请到足够的内存,就会抛出OOM异常。现在我们把代码改成多线程,并且调整参数为2m,-Xss2m,就可以看见OOM异常了,因为每个线程分配的内存越大,栈空间可容纳的线程总数量就越少,越容易产生内存溢出,那反之的话如果内存不够的情况,可以调小该参数来达到支撑更多线程的目的。
public class OOM {public static void main(String[] args) {while (true){new Thread(() -> dontStop()).start();}}static void dontStop(){try {TimeUnit.HOURS.sleep(5);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

结果如下:

JVMDUMP039I ????????"systhrow",????"java/lang/OutOfMemoryError",?? 2024/04/26 17:19:54 - ????

3.直接内存溢出

直接内存并不是虚拟机运行时数据区域的一部分,也不是《Java虚拟机规范》中内定义的内存区域,并且不受堆内存大小的限制,但是受到机器内存大小的限制。比如常见在NIO中可以使用native函数直接分配堆外内存,就有可能导致OOM的问题。那直接内存的大小可以通过参数来指定,那如果你不指定的话,他默认就和java堆内存最大值一样,直接内存导致内存溢出一个最明显的特征就是dump文件不会有明显的异常,如果发现OOM之后dump文件很小,而程序中又直接或间接使用了NIO,那么就可以考虑检查一下是不是这方面的原因。


异常信息如下:

java.lang.OutOfMemoryError: Direct buffer memory

代码里使用DirectByteBuffer之类的,如下:

public class OOM {public static void main(String[] args) {List<ByteBuffer> list = new ArrayList<>();while (true){list.add(ByteBuffer.allocate(1024*1024*20));}}
}

4. 元空间溢出

JDK8之后使用Metaspace来代替永久代,Metaspace是方法区在Hotspot的实现。Metaspace不在虚拟机内存,而是使用本地内存,也就是JDK8中的ClassMetadata,被存储在叫做Metaspacenativr memory
比如我们可以这样设置元空间的大小
-XX:MetaspaceSize=50m -XX:MaxMetaspaceSize=50m(1.8版本jdk)
1.8版本之前方法区存在于永久代,1.8版本之后取消了永久代的概念,如果是之前的版本的话,可以通过设置PermSize大小来设置永久代的大小。
代码:

public class OOM {public static void main(String[] args) {while (true){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(OOM.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, objects);}});enhancer.create();}}}

结果:

Exception in thread "main" org.springframework.cglib.core.CodeGenerationException: java.lang.OutOfMemoryError-->Metaspaceat org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:511)at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363)at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585)at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:131)at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572)at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:387)at OOM.main(OOM.java:23)

5.GC OOM

GC OOM是由于JVM在GC时,对象过多导致内存溢出。
代码如下:

public class OOM {public static void main(String[] args) {ExecutorService executorService = Executors.newFixedThreadPool(15);for (int i = 0; i < Integer.MAX_VALUE; i++) {executorService.execute(() -> {try {Thread.sleep(20000);} catch (InterruptedException e) {throw new RuntimeException(e);}});}}}

异常信息:

java.lang.OutOfMemoryError: GC overhead limit

这篇关于哪些场景会发生OOM异常的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/939638

相关文章

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

Thymeleaf:生成静态文件及异常处理java.lang.NoClassDefFoundError: ognl/PropertyAccessor

我们需要引入包: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>sp

深入理解数据库的 4NF:多值依赖与消除数据异常

在数据库设计中, "范式" 是一个常常被提到的重要概念。许多初学者在学习数据库设计时,经常听到第一范式(1NF)、第二范式(2NF)、第三范式(3NF)以及 BCNF(Boyce-Codd范式)。这些范式都旨在通过消除数据冗余和异常来优化数据库结构。然而,当我们谈到 4NF(第四范式)时,事情变得更加复杂。本文将带你深入了解 多值依赖 和 4NF,帮助你在数据库设计中消除更高级别的异常。 什么是

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法

消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法   消除安卓SDK更新时的“https://dl-ssl.google.com refused”异常的方法 [转载]原地址:http://blog.csdn.net/x605940745/article/details/17911115 消除SDK更新时的“

PostgreSQL核心功能特性与使用领域及场景分析

PostgreSQL有什么优点? 开源和免费 PostgreSQL是一个开源的数据库管理系统,可以免费使用和修改。这降低了企业的成本,并为开发者提供了一个活跃的社区和丰富的资源。 高度兼容 PostgreSQL支持多种操作系统(如Linux、Windows、macOS等)和编程语言(如C、C++、Java、Python、Ruby等),并提供了多种接口(如JDBC、ODBC、ADO.NET等

JVM 常见异常及内存诊断

栈内存溢出 栈内存大小设置:-Xss size 默认除了window以外的所有操作系统默认情况大小为 1MB,window 的默认大小依赖于虚拟机内存。 栈帧过多导致栈内存溢出 下述示例代码,由于递归深度没有限制且没有设置出口,每次方法的调用都会产生一个栈帧导致了创建的栈帧过多,而导致内存溢出(StackOverflowError)。 示例代码: 运行结果: 栈帧过大导致栈内存

当你输入一个网址后都发生什么

原文:http://igoro.com/archive/what-really-happens-when-you-navigate-to-a-url/  作为一个软件开发者,你一定会对网络应用如何工作有一个完整的层次化的认知,同样这里也包括这些应用所用到的技术:像浏览器,HTTP,HTML,网络服务器,需求处理等等。 本文将更深入的研究当你输入一个网址的时候,后台到底发生了一件件什么样的事~

org.hibernate.hql.ast.QuerySyntaxException:is not mapped 异常总结

org.hibernate.hql.ast.QuerySyntaxException: User is not mapped [select u from User u where u.userName=:userName and u.password=:password] 上面的异常的抛出主要有几个方面:1、最容易想到的,就是你的from是实体类而不是表名,这个应该大家都知道,注意

C++第四十七弹---深入理解异常机制:try, catch, throw全面解析

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】 目录 1.C语言传统的处理错误的方式 2.C++异常概念 3. 异常的使用 3.1 异常的抛出和捕获 3.2 异常的重新抛出 3.3 异常安全 3.4 异常规范 4.自定义异常体系 5.C++标准库的异常体系 1.C语言传统的处理错误的方式 传统的错误处理机制: