Java 内存溢出(一)原因、复现、排查

news2025/1/17 8:54:16

目录

    • 一、内存溢出原因
    • 二、内存溢出实例
      • 1、堆溢出
      • 2.虚拟机栈和本地方法栈溢出
      • 3.方法区和运行时常量池溢出
      • 4.本机直接内存溢出
    • 三、内存溢出排查

内存溢出: 是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。这篇文章整理自《深入理解 java 虚拟机》。

一、内存溢出原因

内存溢出就是内存不够,引起内存溢出的原因有很多种,常见的有以下几种:

  1. 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
  2. 集合类中有对对象的引用,使用完后未清空,使得 JVM 不能回收;
  3. 代码中存在死循环或循环产生过多重复的对象实体;
  4. 使用的第三方软件中的 BUG;
  5. 启动参数内存值设定的过小。

当然实际情况中内存溢出的原因就太多了。

请添加图片描述

以上的图是基于 java7 来描述的,从上面这张图我们能够得到如下信息:java 虚拟机把内存分为 5 个模块。

(1)程序计数器:程序计数器是线程私有的,主要作用是通过改变这个计数器的值来选取下一条需要执行的字节码指令。既然每个线程都有一个,那么这些线程的计数器是互不影响的,也不会抛出任何异常。

(2)虚拟机栈和本地方法栈:虚拟机栈描述的是 java 方法执行的内存模型,每个方法在执行的时候都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。本地方法栈与虚拟机栈的区别是,虚拟机栈为虚拟机执行 java 方法服务,而本地方法栈则为虚拟机提供 native 方法服务。

在单线程的操作中,无论是由于栈帧太大,还是虚拟机栈空间太小,当栈空间无法分配时,虚拟机抛出的都是 StackOverflowError 异常,而不会得到 OutOfMemoryError 异常。而在多线程环境下,则会抛出 OutOfMemoryError 异常。

(3)java 堆和方法区:java 堆区主要存放对象实例和数组等,方法区保存类信息、常量、静态变量等等。运行时常量池也是方法区的一部分。这两块区域是线程共享的区域,只会抛出 OutOfMemoryError。

二、内存溢出实例

1、堆溢出

既然堆是存放实例对象的,那我们就无限创建实例对象。这样堆区迟早会满。

执行时需要设置VM参数:-Xmx10M,限制最大堆内存为10M

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

异常内容:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:261)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
	at java.util.ArrayList.add(ArrayList.java:458)
	at com.demo.HeapOOM.main(HeapOOM.java:6)

因为我提前设置了堆区内存限制,所以无限创建就会抛出异常。

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

Java 虚拟机规范中描述了两种异常:

如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出 StackOverflowError 异常。如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出 OutOfMemoryError 异常。

第一种我们只需要使用方法递归调用即可模拟:

public class StackOutOfMemoryError {
    public static void main(String[] args) {
        test();
    }
    private static void test() {
        System.out.println("StackOverflowError 异常测试");
        test();
    }
}

异常内容:

Exception in thread "main" java.lang.StackOverflowError
	at sun.nio.cs.UTF_8$Encoder.encodeLoop(UTF_8.java:691)
	at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:579)
	at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:271)
	at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
	at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
	at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
	at java.io.PrintStream.write(PrintStream.java:526)
	at java.io.PrintStream.print(PrintStream.java:669)
	at java.io.PrintStream.println(PrintStream.java:806)
	at com.demo.StackOutOfMemoryError.test(StackOutOfMemoryError.java:6)

第二种也可以递归调用模拟,但是使用的是类直接调用:

public class JavaVMStackSOF {
    private int stackLength = 1;
    public void stackLeak() {
        stackLength++;
        stackLeak();
    }
    public static void main(String[] args) {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        oom.stackLeak();
    }
}

异常内容:

Exception in thread "main" java.lang.StackOverflowError
	at com.demo.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:5)

3.方法区和运行时常量池溢出

执行时需要设置VM参数:-Xmx10M,限制最大堆内存为10M

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class JavaMethodAreaOOM {
    private static class User {}
    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(User.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method,
                                        Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, args);
                }
            });
            enhancer.create();
        }
    }
}

异常内容:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.lang.AbstractStringBuilder.<init>(AbstractStringBuilder.java:68)
	at java.lang.StringBuffer.<init>(StringBuffer.java:116)
	at org.objectweb.asm.Type.getDescriptor(Unknown Source)
	at net.sf.cglib.core.ClassEmitter.declare_field(ClassEmitter.java:193)
	at net.sf.cglib.proxy.MethodInterceptorGenerator.generate(MethodInterceptorGenerator.java:94)
	at net.sf.cglib.proxy.Enhancer.emitMethods(Enhancer.java:994)
	at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:498)
	at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
	at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
	at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
	at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
	at com.demo.JavaMethodAreaOOM.main(JavaMethodAreaOOM.java:22)

4.本机直接内存溢出

执行时需要设置VM参数:-Xmx10M,限制最大堆内存为10M

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class DirectMemoryOOM {
    private static final int _1MB = 1024 * 1024;
    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (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.demo.DirectMemoryOOM.main(DirectMemoryOOM.java:12)

DirectMemory 容量可通过 -XX:MaxDirectMemorySize指定,如果不指定,则默认与 Java 堆最大值(-Xmx 指定)一样。

三、内存溢出排查

排查最主要的就是检查代码,而且内存溢出往往都是代码的问题。当然以下几点都是需要注意的:

(1)内存中加载的数据量过于庞大,如一次性从数据库取出过多数据;

(2)集合类中有对对象的引用,使用完后未清空,是的 JVM 不能回收;

(3)代码中存在死循环或循环产生过多重复的对象实体;

(4)使用的第三方软件中的 BUG;

(5)启动参数内存值设定的过小。

内存溢出解决方法:

方法一:修改 JVM 启动参数,直接增加内存,暂时解决问题;

方法二:检查错误日志,定位可能发生内存溢出的位置,优化代码;

方法三:如果设置了内存参数 -XX:+HeapDumpOnOutOfMemoryError,当内存溢出时会产生 .hprof 文件(记录了 Java 进程在某个时间内的快照),可以通过 MAT 工具进行分析,优化代码。

整理完毕,完结撒花~





参考地址:

1.java内存溢出,https://blog.csdn.net/u014401141/article/details/122825443

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

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

相关文章

[附源码]计算机毕业设计JAVA基于新高考模式下的排课系统

[附源码]计算机毕业设计JAVA基于新高考模式下的排课系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; S…

强化学习论文分析5---多基站_强化学习_联邦学习_计算卸载

目录一、文章概述二、理论模型1.系统目标2.约束条件3.公式推导(1)任务量(2)卸载率(3)本地能耗(4)传输能耗(5)MEC计算能耗(6)总述三、算法架构----多基站联合强化学习1.网络结构图2.算法总述3.Actor网络(1).输入状态(2).输出动作4.Critic网络(1).环境奖励5.伪代码四、算法架构--…

信号线多长算长呢——之上升沿与时延的爱恨情仇

忆往昔岁月&#xff0c;看着PCB上弯弯曲曲的走线&#xff0c;看着书中所说的端接&#xff0c;想象着日后自己也可以这么牛逼&#xff0c;能够设计出这么复杂的电路。“过来焊板子啦”一句话又将我拉回了现实&#xff0c;哎&#xff0c;过来吸一会我们硬件攻城狮的精神鸦片——松…

实验四 软中断信号及处理

1.利用sleep、pause、alarm函数设定闹钟&#xff0c;定时显示信息。 #include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<signal.h> int main(){int ret;alarm(50);sleep(30);retalarm(10);printf("%d\n",ret);pause();pri…

C++11

1. C11简介 相比于 C98/03&#xff0c;C11则带来了数量可观的变化&#xff0c;其中包含了约140个新特性&#xff0c;以及C03标准中约600个缺陷的修正&#xff0c;这使得C11更像是从C98/03中孕育出的一种新语言。相比较而言&#xff0c;C11能更好地用于系统开发和库开发、语法更…

玩机搞机---脱离电脑 用手机给手机刷机 解锁bl 获取root的方法教程

友友们有时候手机出问题需要刷机而手头缺没有电脑的情况下该如何解决呢&#xff0c;今天的话题就聊聊 这方面的常识。其实类似手机给手机刷机的方法有很多&#xff0c;但原理都是一样的&#xff0c;有时候可以起到应急解决方法&#xff0c; 一 需要的工具与准备工作; 手机A …

长尾词挖掘免费工具-长尾关键词挖掘词

什么是关键词&#xff1f;在 SEO&#xff0c;搜索引擎优化的范畴里&#xff0c;关键词指的是用户输入到搜索框内的那一个&#xff0c;或者几个词&#xff0c;目的是为了找到他要的答案。搜索引擎收到用户发送的这几个词&#xff0c;或者说关键词后&#xff0c;就会试图找到最合…

同惠TH9310耐压测试仪应用举例

TH9310交直流耐压绝缘测试仪是一款小功率经济型智能安规测试仪器。体积小、重量轻、外形美观、操作简便。TH9320产品可广泛应用于家用电器、变压器、电气设备、元器件的安全性能检查。 应用举例&#xff1a; ■ 自动化测试系统 ■ 家用电器 ■ 变压器、电机 ■ 电气设备 …

Postman高频面试题及答案汇总(接口测试必备)

Postman在软件测试的面试中&#xff0c;可以说是必考题了&#xff0c;既然是高频考题&#xff0c;当然得为粉丝宝宝们整理一波题库喽~ 一、Postman在工作中使用流程是什么样的&#xff1f; 二、你使用过Postman的哪些功能&#xff1f; 三、Postman如何管理测试环境&#xff…

【改进灰狼优化算法】基于协调探索和开发能力的改进灰狼优化算法求解单目标优化问题(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

1.QML Hello world

目录1. 如何显示HelloWorld&#xff1f;2. QML工程如何创建&#xff1f;3. QML HelloWorld工程里有什么文件&#xff1f;1. 如何显示HelloWorld&#xff1f; 本系列文章基于Windows11Qt6.3&#xff0c;GUI开发第一步&#xff0c;显示一个Hello world。 import QtQuick //Qt5 需…

数据结构与算法是什么?

人们常说&#xff1a; 程序 数据结构 算法 当遇到一个问题&#xff0c;或者有一个需求时&#xff0c;要设计程序来解决问题&#xff0c;重要的一步就是设计算法&#xff0c;并选择或者说设计相应数据结构来实现算法。 一、数据结构 数据结构在问题解决中主要用来&#xf…

第一章三层交换应用

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。个人爱好: 编程&#xff0c;打篮球&#xff0c;计算机知识个人名言&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石…

CSS的选择器(超详细)

目录 一、常用的选择器 1.元素选择器 2.类选择器(class选择器) 3.id选择器 4.通配符选择器 二、群组选择器 三、关系选择器 1.后代选择器 2.子代选择器 3.相邻兄弟选择器 4.通用兄弟选择器 5.案例 四、属性选择器 五、伪类选择器 1.常用的伪类选择器 2.否定伪类 3.元…

智慧农业大数据平台:农业中的“大智慧”

智慧农业是现代化农业发展的重要途径&#xff0c;是利用物联网等现代信息技术提升农业生产管理水平&#xff0c;实现传统农业转型升级的重要措施。近年来&#xff0c;我国食品安全问题频发&#xff0c;究其根本原因&#xff0c;既有商家过度逐利的过错&#xff0c;也有农产品在…

MySQL 不相关子查询怎么执行?

1. 概述 从现存的子查询执行策略来看&#xff0c;半连接 (Semijoin) 加入之前&#xff0c;不相关子查询有两种执行策略&#xff1a; 策略 1&#xff0c;子查询物化&#xff0c;也就是把子查询的执行结果存入临时表&#xff0c;这个临时表叫作物化表。 explain select_type …

Linux: network: tcp_rmem/rmem_default

文章目录tcp_rmem - 取值是&#xff1a;3个整数向量: min, default, maxmindefault&#xff1a;maxrmem_defaultrmem_max具体的用法相关的方法tcp_rmem - 取值是&#xff1a;3个整数向量: min, default, max min TCP sockets使用的最小接收缓存大小。这个最小值的作用是在&am…

PowerPC平台移植RTL8822BU

目录编译驱动文件修改Makefile修改代码安装前置工具编译openssl编译libnl解决报错编译wpa_supplicant解决报错编译hostapd移植入嵌入式编译驱动文件 修改Makefile 修改代码 由于我这边kernel用的是比较老的&#xff0c;有些接口不支持&#xff0c;所以需要做一些处理 关于is…

K_A07_001 基于 STM32等单片机驱动A4988模块按键控制步进电机正反转

目录 一、资源说明 二、基本参数 1、参数 2、引脚说明 三、驱动说明 SETP时序 对应程序: 细分说明 程序 四、部分代码说明 1、接线说明 1.1、STC89C52RCA4988模块 1.2、STM32F103C8T6A4988模块 五、基础知识学习与相关资料下载 六、视频效果展示与程序资料获取 七、项目…

基于深度学习的人脸表情识别的AR川剧变脸(二)

在一中&#xff0c;我们训练了一个&#xff0c;可以识别angry、disgust、fear、happy、sad、surprised、normal七种人脸表情。 本文将建立在表情识别的基础上&#xff0c;设计一款AR变脸效果的软件&#xff0c;通过前置摄像头获取人脸图像&#xff0c;使用训练好的模型进行人脸…