深入解析发生 OOM 的三大场景

深入解析 OOM 的三大场景

    • 什么是 OOM?
    • 一、堆内存溢出 ( Heap OOM )
      • 原因分析
      • 解决方案
    • 二、栈内存溢出(Stack OOM)
      • 原因分析
      • 解决方案
    • 三、方法区内存溢出(Metaspace OOM)
      • 原因分析
      • 解决方案

在Java应用程序开发中,OutOfMemoryError(OOM)是一个令人头痛的问题。当JVM中的内存无法满足应用程序的需求时,就会抛出这个错误。本文将深入探讨OOM的三大场景:堆内存溢出、方法区内存溢出和栈内存溢出,并分析它们的原因,提供相应的实战解决方案。

什么是 OOM?

OOM 的全称是 Out Of Memory,那我们的内存区域有哪些会发生 OOM 呢?我们可以从内存区域划分图上,看一下彩色部分
在这里插入图片描述

可以看到除了程序计数器,其他区域都有OOM溢出的可能。但是最常见的还是发生在堆内存溢出、方法区内存溢出和栈内存溢出,主要是在堆上。

在这里插入图片描述

另外,我们常说的 OOM 异常,其实是 Error

在这里插入图片描述

一、堆内存溢出 ( Heap OOM )

Java 堆用于存储对象实例,我们只要不断的创建对象,并且保证 GC Roots 到对象之间有可达路径来避免 GC 清除这些对象,那随着对象数量的增加,总容量触及堆的最大容量限制后就会产生内存溢出异常。

Java 堆内存的 OOM 异常是实际应用中最常见的内存溢出异常。

/*** JVM参数:-Xmx10m*/
public class JavaHeapSpaceDemo {static final int SIZE = 100 * 1024 * 1024;public static void main(String[] a) {int[] i = new int[SIZE];}
}

代码试图分配容量为 100M 的 int 数组,如果指定启动参数 -Xmx10m,分配内存就不够用,就类似于将 XXXL 号的对象,往 S 号的 Java heap space 里面塞。

原因分析

  1. 对象过多:应用程序创建了大量的对象,并且这些对象长时间存活,导致堆内存不足。
  2. 内存泄漏:应用程序中存在内存泄漏,即长时间无法释放不再使用的对象,导致堆内存持续占用。
  3. 超出预期的访问量/数据量:通常是上游系统请求流量飙升,常见于各类促销/秒杀活动,可以结合业务流量指标排查是否有尖状峰值

解决方案

针对大部分情况,通常只需要通过 -Xmx 参数调高 JVM 堆内存空间即可。如果仍然没有解决,可以参考以下情况做进一步处理:

  1. 优化代码:减少不必要的对象创建,避免过大的集合和数组。
  2. 如果是内存泄漏,需要找到持有的对象,修改代码设计,比如关闭没有释放的连接
  3. 如果是业务峰值压力,可以考虑添加机器资源,或者做限流降级。

二、栈内存溢出(Stack OOM)

栈内存溢出通常与线程的执行和递归调用有关。

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

原因分析

  1. 递归调用过深(最常见原因):递归算法实现不当,导致递归深度过大,超出了线程栈的大小限制。
  2. 线程创建过多:应用程序创建了大量的线程,并且每个线程的栈内存分配过多,导致系统资源耗尽。

解决方案

  1. 修复引发无限递归调用的异常代码, 通过程序抛出的异常堆栈,找出不断重复的代码行,按图索骥,修复无限递归 Bug

  2. 排查是否存在类之间的循环依赖

  3. 通过 JVM 启动参数 -Xss 增加线程栈内存空间, 某些正常使用场景需要执行大量方法或包含大量局部变量,这时可以适当地提高线程栈空间限制

三、方法区内存溢出(Metaspace OOM)

方法区内存溢出通常与类的加载和元数据的存储有关。

JDK 1.8 之前会出现 Permgen space,该错误表示永久代(Permanent Generation)已用满,通常是因为加载的 class 数目太多或体积太大。随着 1.8 中永久代的取消,就不会出现这种异常了。

Metaspace 是方法区在 HotSpot 中的实现,它与永久代最大的区别在于,元空间并不在虚拟机内存中而是使用本地内存,但是本地内存也有打满的时候,所以也会有异常。

/*** JVM Options: -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m*/
public class MetaspaceOOMDemo {public static void main(String[] args) {while (true) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(MetaspaceOOMDemo.class);enhancer.setUseCache(false);enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {//动态代理创建对象return methodProxy.invokeSuper(o, objects);});enhancer.create();}}
}

借助 Spring 的 GCLib 实现动态创建对象

Exception in thread "main" org.springframework.cglib.core.CodeGenerationException: java.lang.OutOfMemoryError-->Metaspace

方法区溢出也是一种常见的内存溢出异常,在经常运行时生成大量动态类的应用场景中,就应该特别关注这些类的回收情况。这类场景除了上边的 GCLib 字节码增强和动态语言外,常见的还有,大量 JSP 或动态产生 JSP 文件的应用(远古时代的传统软件行业可能会有)、基于 OSGi 的应用(即使同一个类文件,被不同的加载器加载也会视为不同的类)等。

原因分析

  1. 加载过多的类:每个类在加载到JVM时都会占用一定的方法区空间。如果程序加载了大量的类,那么方法区可能会被占满,导致OOM。
  2. 类加载器泄漏:如果类加载器没有正确地释放已经加载的类,那么这些类将一直占用方法区空间,导致方法区溢出。
  3. 动态生成类:在使用诸如JSP、反射或ASM等技术动态生成类时,如果生成过多的类或频繁地生成和卸载类,可能会导致方法区溢出

解决方案

  • 限制方法区大小:通过-XX:MaxMetaspaceSize参数设置方法区的最大值,避免无限制增长。这需要根据应用程序的实际情况进行调整。
  • 检查类加载器实现:确保自定义的类加载器正确实现了资源的释放,避免类加载器泄露。同时,注意检查和升级可能导致泄露的第三方库。
  • 优化类加载策略:按需加载和卸载类,避免不必要的类加载。可以考虑使用模块化技术(如OSGi)来管理类的加载和卸载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/870894.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python实现http get pos download

python实现http get post download 使用requests, 加上重试机制,超时机制. #!/usr/bin/python3 # -*- coding: UTF-8 -*-import requests import sys import json import os import logging import timedef httpGet(urlStr, headers None, params None, data None, isRaise…

记录一次Nginx的使用过程

一、Docker安装配置nginx 1.拉取镜像 docker pull nginx2.创建挂载目录 启动前需要先创建Nginx外部挂载目录文件夹 主要有三个目录 conf:配置文件目录log:日志文件目录html:项目文件目录(这里可以存放web文件) 创建挂…

oslo_i18n学习小结

背景 代码均为开源代码 基于yoga版本,需要对openstack某服务做翻译,了解到oslo_i18n有翻译功能,配置oslo_i18n来给组件进行翻译 用法 用法 每个服务自己会带一个i18n.py的文件,如果要对日志进行翻译,从i18n导入_&…

逆变-TI视频课笔记

目录 1、全桥逆变 1.1、全桥逆变SPWM仿真 2、半桥逆变 2.1、本课小结 3、多重逆变(间接的“交-直-交-直”变流) 3.1、多电平逆变的目的 3.2、单逆变桥 3 电平控制时序 3.3、大功率设备的功率因数 3.4、本课小结 视频链接:文字…

算法训练(leetcode)第二十八天 | 509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

刷题记录 509. 斐波那契数递归循环动态规划 70. 爬楼梯746. 使用最小花费爬楼梯 509. 斐波那契数 leetcode题目地址 递归 时间复杂度&#xff1a; O ( n ) O(n) O(n) 空间复杂度&#xff1a; O ( n ) O(n) O(n) // c class Solution { public:int fib(int n) {if(n<2)…

Kafka配置SSL信道加密

kafka配置SASL认证 Kafka单机配置SSL认证 使用脚本生成SSL证书 执行ssl.sh # 配置SSL配置文件 cp server.properties ssl.properties# 修改配置文件SSL内容 listenersSSL://kafka-test:9092 advertised.listenersSSL://kafka-test:9092 ssl.keystore.location/root/config/cer…

linux中vim切换输入中文

linux中vim切换输入中文 遇到问题 在虚拟机linux下vim 编辑器中注释的时候无法使用中文 解决方案 Linux系统中的vim编辑器中安装中文输入法软件包 1.在终端中输入以下命令 sudo apt-get install fcitx fcitx-bin fcitx-table-wubi fcitx-table-wbpy2. 安装完成后&#xf…

Zed 编辑器发布了原生 Linux 版本

由 Rust 编写、GPU 加速的 Zed 文本编辑器终于提供了正式的 Linux 原生版本&#xff01;在过去的几个月里&#xff0c;Zed 的 Linux 支持取得了长足的进步&#xff0c;现在已经进入了更正式的阶段。 今天&#xff0c;这款由前 Atom 开发人员创建的现代开源代码编辑器现在在 Li…

vue vite+three在线编辑模型导入导出

文章目录 序一、1.0.0版本1.新增2.编辑3.导出4.导入 二、2.0.0版本1. 修复模型垂直方向放置时 模型会重合4. 修复了导出导入功能 现在是1:1导出导入5. 新增一个地面 视角看不到地下 设置了禁止编辑地面 地面设置为圆形6. 新增功能 可选择基本圆形 方形 圆柱形等模型以及可放置自…

HUGS环境配置

1. 介绍 HUGS: Holistic Urban 3D Scene Understanding via Gaussian Splatting 基于 RGB 图像对城市场景进行整体理解是一个具有挑战性但又很重要的问题。它包括理解几何和外观&#xff0c;以实现新颖的视图合成、解析语义标签和跟踪移动物体。尽管取得了长足的进步&#xf…

C# 的TaskScheduler

在C#中&#xff0c;TaskScheduler 是一个抽象类&#xff0c;用于控制任务的执行方式&#xff0c;特别是它们如何被安排到线程池中的线程上执行。 TaskScheduler 负责将 Task 对象排队并决定何时、以何种方式执行这些任务。 TaskScheduler 的作用 调度任务&#xff1a;将任务…

querylist多线程采集curlMulti时,报错Curl error(60)

前言 在使用querylist多线程采集的时候&#xff0c;报错: Curl error(60)。测试了下用http时没有问题&#xff0c;https时有问题。其原因在于多线程采集库引用的另一个库有问题。需要手动更改。 解决 找到&#xff1a;vendor/ares333/php-curl/src/Curl.php 文件&#xff0c…

网络 闲聊

闲谈 闲话 网络安全——>网络空间安全 网络空间&#xff1a;一个由信息基础设备组成互相依赖的网络 继&#xff1a;海、陆、空、天、的第五大空间 信息安全的一个发展&#xff1a; 通信保密阶段---计算机安全---信息系统安全---网络空间安全 棱镜门事件 棱镜计划&…

Visual Studio Code:深度解析与开发者的新宠

在计算机行业中&#xff0c;开发工具的选择至关重要&#xff0c;它直接影响到开发者的效率和项目的质量。近年来&#xff0c;Visual Studio Code&#xff08;简称VSCode&#xff09;凭借其强大的功能和灵活的定制性&#xff0c;在众多编辑器中脱颖而出&#xff0c;成为了开发者…

linux系统php开机自启动 phpfpm

1、关闭当前的php环境&#xff0c;运行命令&#xff0c;下面二选一&#xff0c;根据你自己情况来选 service php-fpm stop 或 systemctl stop php-fpm 2、运行命令vim /etc/systemd/system/phpfpm.service&#xff0c;输入以下代码,注意php-fpm路径需要改成自己的路径 [Unit]…

Redis原子计数器incr,防止并发请求

一、前言 在一些对高并发请求有限制的系统或者功能里&#xff0c;比如说秒杀活动&#xff0c;或者一些网站返回的当前用户过多&#xff0c;请稍后尝试。这些都是通过对同一时刻请求数量进行了限制&#xff0c;一般用作对后台系统的保护&#xff0c;防止系统因为过大的流量冲击…

Twitter API 使用教程:入门到实践

Twitter API为开发者提供了丰富的接口&#xff0c;用于访问Twitter上的公开数据和实现特定功能。从获取推文到用户认证&#xff0c;Twitter API在数据挖掘、社交分析和应用开发中扮演着重要角色。 关键词 Twitter API, 开发者指南&#xff0c;社交媒体&#xff0c;数据访问 …

elementary os 8 2024年07月新动态

具体信息请登录官网查询 **OS 7更新** Photos 8已经作为Flatpak应用发布到AppCenter。这意味着你可以通过从AppCenter安装Flatpak版本来继续接收Photos的更新&#xff0c;即使在旧版本的elementary OS上&#xff0c;而且Photos现在也很容易为那些运行除elementary OS之外的Lin…

Java中的Set系列集合超详解

Set List是有序集合的根接口&#xff0c;Set是无序集合的根接口&#xff0c;无序也就意味着元素不重复。更严格地说&#xff0c;Set集合不包含一对元素e1和e2 &#xff0c;使得e1.equals(e2) &#xff0c;并且最多一个空元素。   使用Set存储的特点与List相反&#xff1a;元素…

腾讯云如何设置二级域名?

什么是二级域名&#xff1f; 例如我已申请的域名为&#xff1a; test.com //顶级域名 现在我开发的应用要部署到二级域名&#xff1a; blog.test.com 1、打开腾讯云控制台的我的域名&#xff0c;然后点击解析 2、在我的解析页面点击添加记录&#xff0c;然后需注意红色方框处…