【JVM】如何定位、解决内存泄漏和溢出

目录

1.概述

2.堆溢出、内存泄定位及解决办法

2.1.示例代码

2.2.抓堆快照

2.3.分析堆快照


1.概述

常见的几种JVM内存溢出的场景如下:

  • Java堆溢出: 错误信息: java.lang.OutOfMemoryError: Java heap space 原因:Java对象实例在运行时持续创建,但不再使用的对象没有及时被垃圾回收器回收,导致堆内存耗尽。 解决方案:增加堆内存大小(-Xms和-Xmx参数),优化对象生命周期管理,减少不必要的大对象或者长时间存在的临时对象。

  • 永久代/元空间溢出(取决于Java版本): 在Java 8及以前版本中,永久代存储类信息、常量池、静态变量等数据,若空间不足会抛出java.lang.OutOfMemoryError: PermGen space错误。 在Java 8之后,永久代已被元空间取代,元空间直接使用本地操作系统内存,可能出现java.lang.OutOfMemoryError: Metaspace。 解决方案:增大永久代或元空间的大小,检查代码是否有大量动态加载类或者反射操作生成过多类信息的情况。

  • 栈空间溢出: 错误信息: java.lang.StackOverflowError 原因:递归调用过深或线程栈帧过大,导致线程栈空间耗尽。 解决方案:调整栈的大小(-Xss参数),改进算法避免深度递归,合理控制线程数量或每个线程栈的大小。

首先栈溢出定位很简单,直接异常栈就会告诉,去调整代码逻辑即可。这里着重要聊一下的是元空间溢出和堆溢出。

元空间溢出

JDK1.8及其以后版本,元空间替代了永久代,其主要用于存储类的元数据信息,包括类的结构信息(如字段、方法、接口、常量池等)、运行时常量池、方法字节码、静态变量等。也就是说类被加载了,其相关信息就会存在元空间中。

此处也许有些读者会有疑问:

类是要在被用到的时候才会加载,也就是一般我们new对象的时候对应的类才会被加载,那么存在元空间在堆之前被撑爆的情况吗?

答:

当然是存在的,只要你的元空间比你的堆小,或者频繁用Class.forName()、ClassLoader.loadClass()等反射的手法来加载类,但是不new对象,也能把元空间撑爆了。

元空间溢出其实是比较难遇见的,但是定位方法其实不难,直接代码全局搜Class.forName之类的语法基本就能定位元凶。

接下来本文要讲的重点是生产中最容易遇见的一种JVM内存溢出——堆溢出,以及比堆溢出藏得更深的隐形杀手——内存泄漏,这两者如何定位以及解决。

2.堆溢出、内存泄定位及解决办法

2.1.示例代码

直接的堆溢出从异常栈信息里是能看出哪里造成的OOM,很容易定位:

难定位的是哪种?怕的是内存泄漏,也就是堆还没有撑爆,但是就是在要爆不爆之间徘徊,造成频繁的GC,由于GC的时候是要”Stop The World“,会暂停所有JAVA线程的工作,这自然会浪费CPU资源,外界的感知就是”变慢了“。这里我们详细的来聊一聊如何定位内存泄漏的问题。

测试代码:

//定义一个类,该类中一旦调用一个方法,就会持续让List持有一个个1024KB大小的内存空间,但是又不会直接撑爆heap
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.ArrayList;
​
public class MyUser {private Byte[] bytes;
​ArrayList<byte[]> list = new ArrayList();
​public static final int OBJECT_SIZE = 1024 * 1024; // 每个对象占用1MB空间public static final double HEAP_UTILIZATION_RATIO = 0.8; // 目标堆利用率
​public MyUser(){}
​public void callTest(){try {MemoryMXBean memoryMxBean = ManagementFactory.getMemoryMXBean();long maxMemory = Runtime.getRuntime().maxMemory();
​while (true) {// 检查当前堆内存使用情况,如果已超过目标利用率,则退出循环long currentHeapUsage = memoryMxBean.getHeapMemoryUsage().getUsed();if ((double) currentHeapUsage / maxMemory >= HEAP_UTILIZATION_RATIO) {System.out.println("当前堆内存使用率达到目标利用率,程序即将退出...");break;}
​// 创建一个大对象byte[] largeObject = new byte[OBJECT_SIZE];// 将大对象添加到列表中list.add(largeObject);
​// 添加一个延时,模拟其他操作,便于观察Thread.sleep(100); // 等待100毫秒
​// 可以在此处添加额外的日志输出或监控代码,用于记录GC信息和内存状态}
​// 清理资源,防止后续分析时误判list.clear();} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
​
//用junit开始测试
@Test
public void test02() throws Exception{MyUser myUser = new MyUser();myUser.callTest();

2.2.抓堆快照

运行上面的示例代码,打开jvisualVM,开始监控程序,可以看到:

垃圾回收是有在进行的,而且频率不低,但是堆的大小一直在扩,被占用率一直在攀升,说明并没有被回收掉,存在严重的内存泄露。

这时候就需要把堆的dump抓下来看看了。右上角有抓heap dump的选项。

2.3.分析堆快照

通过MAT看看了,看看到底是有哪些东西占着内存一直没被回收掉。

MAT是eclipse旗下的一款heap的分析工具,可以用来专门分析heap dump。下载地址:

Eclipse Memory Analyzer | projects.eclipse.org

MAT和JDK有版本适配关系!千万别下错了,作者用的JDK,下载的1.8.1版本:

还要注意下载的安装包和操作系统之间也是有严格的适配关系的,作者第一次就下成了x86而不是x86_64,确定好自己的操作系统平台下对应的:

用MAT打开抓下来的heap dump:

工具会分析显示除怀疑内存泄漏的地方:

其实从饼状图上已经可以看出端倪,饼状图显示了可能存在内存泄漏的对象和该对象持有的内存的对比,这个对象自身占的内存大小只有浅灰色的一小条,但是其持有的内存居然达到了300多MB,很明显的内存泄漏的情况。

我们初步断定了存在内存泄漏,接下来当然是要定位具体位置,然后才好解决它。

展开详细信息,可以看到怀疑是Main线程上的一个MyUser类型里面的一个类型为ArrayList名叫list的成员变量造成了内存泄漏:

接下来去看这里的代码逻辑就行了。

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

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

相关文章

Open3D(C++) 基于随机抽样与特征值法的点云平面稳健拟合方法

目录 一、算法原理1、论文概述2、参考文献二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的GPT爬虫。 一、算法原理 1、论文概述 针对点云数据含有异常值且传统拟合方法拟合结果不理想的情…

【算法】字典序超详细解析(让你有一种相见恨晚的感觉!)

目录 一、前言 二、什么是字典序 &#xff1f; ✨字典序概念 ✨深度理解字典序 ✨字典序排序的重要性和应用场景 三、常考面试题 ✨ 下一个排列 ✨ 字典数排序 ✨ 字典序最小回文串 四、共勉 一、前言 经常刷算法题的朋友&#xff0c;肯定会经常看到题目中提到 字典序 这样…

6.java openCV4.x 入门-Mat之局部区域读写及Range和Rect介绍

专栏简介 &#x1f492;个人主页 &#x1f4f0;专栏目录 点击上方查看更多内容 &#x1f4d6;心灵鸡汤&#x1f4d6;我们唯一拥有的就是今天&#xff0c;唯一能把握的也是今天建议把本文当作笔记来看&#xff0c;据说专栏目录里面有相应视频&#x1f92b; &#x1f9ed;文…

小白水平理解面试经典题目1431. Kids With the Greatest Number of Candies【Array类】

1431. 拥有最多糖果的孩子 小白渣翻译 一群孩子手里拿 着不同数目的糖果。你打算额外给每个孩子一些糖果&#xff0c;然后再确定哪些孩子拥有最多的糖果。 给你一个数组 candies &#xff0c;其中 candies[i] 代表第 i 个孩子拥有的糖果数目。另给你一个整数 extraCandies &…

vue源码解析——vue如何将template转换为render函数

Vue 将模板&#xff08;template&#xff09;转换为渲染函数&#xff08;render function&#xff09;是 Vue 编译器的核心功能&#xff0c;它是 Vue 实现响应式和虚拟 DOM 的关键步骤。在 Vue 中&#xff0c;模板&#xff08;template&#xff09;是开发者编写的类似 HTML 的代…

python vtk获取模型角度

在Python中,使用VTK库获取3D模型的角度通常涉及到计算模型的几何参数,如物体的最小外接矩形或边界盒子。以下是一个简单的例子,展示如何使用VTK计算3D模型的边界盒子,从而获取模型的角度: import vtk# 创建一个VTK的PolyData对象,并添加模型数据 polyData = vtk.vtkPoly…

qT 地图显示飞机轨迹

为了在Qt中显示飞机轨迹&#xff0c;你可以使用Qt的地图模块&#xff0c;例如Qt Location。以下是一个简单的示例&#xff0c;展示如何使用Qt地图模块显示飞机的轨迹。 首先&#xff0c;确保你的Qt项目文件(.pro)中包含了以下行来启用Qt Location模块&#xff1a; !include($…

【大数据运维】Hbase shell 常见操作

文章目录 一. DDL1. 表的DDL1.1. 创建表1.2. 删除表 2. 列族的DDL2.1. 增加一个列簇2.2. 删除列族2.3. 修改列族版本&#xff08;ing&#xff09; 二. DML1. 插入与更新数据2. 删除数据3. 清空表 三. DQL1. scan&#xff1a;查一批数据1.1. 查询全部1.2. 过滤rowkey1.3. 过滤列…

HackTheBox-Machines--Wifinetic

文章目录 1 端口扫描2 测试思路3 21端口测试&权限获取4 权限提升方法一方法二&#xff1a; Wifinetic 测试过程 1 端口扫描 nmap -sC -sV 10.129.229.902 测试思路 目标开启了21、22、53端口&#xff0c;并且21端口FTP服务允许匿名登录&#xff0c;所以从21端口开始进行测试…

OpenCV与AI深度学习 | OpenCV中八种不同的目标追踪算法

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;OpenCV中八种不同的目标追踪算法 目标跟踪作为机器学习的一个重要分支&#xff0c;加之其在日常生活、军事行动中的广泛应用&#xff0c;受到…

STM32F4系列单片机的定时器讲解和计数器,PWM信号输出,PWM信号捕获的实现对电机进行控制和监测功能

1.定时器功能介绍&#xff1a; 在控制领域里面&#xff0c;我们可以用信号输出定时器&#xff0c;进行PWM的控制&#xff0c;从而达到控制电机的目的&#xff0c;通过输入捕获功能可以用来接收外部的数字信号&#xff0c;用于测量脉冲宽度、频率或周期等。在这里给大家介绍下&…

【Python基础知识点】Python的浅拷贝和深拷贝

概述 本文主要通过两个简单的代码小例子理解深拷贝和浅拷贝 主体内容 copy 模块提供了浅拷贝和深拷贝的功能。它的主要函数有: copy(x): 返回对象 x 的浅拷贝。 deepcopy(x): 返回对象 x 的深拷贝。 浅拷贝使用 copy(x) 函数,它只复制了最外层的对象,但内层的对象仍然是引用…

缺省参数

缺省参数 缺省参数概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&#xff0c;如果没有指定实 参则采用该形参的缺省值&#xff0c;否则使用指定的实参。 void Func(int a 0) {cout<<a<<endl; } int main() {Func(); // 没有传…

Rust所有权和Move关键字使用和含义讲解,以及Arc和Mutex使用

Rust 所有权规则 一个值只能被一个变量所拥有&#xff0c;这个变量被称为所有者。 一个值同一时刻只能有一个所有者&#xff0c;也就是说不能有两个变量拥有相同的值。所以对应变量赋值、参数传递、函数返回等行为&#xff0c;旧的所有者会把值的所有权转移给新的所有者&#…

共襄盛举!400+组织携手发布「2024集成光子学路线图」

3月25日&#xff0c;麻省理工学院微光子中心与PhotonDelta基金会联合领导&#xff0c;携手全球400余家科技、学术及工业界组织&#xff0c;共同发布了2024年版集成光子学路线图。 该路线图被称为IPSR-I&#xff08;Integrated Photonics System Roadmap – International&#…

面试算法-129-寻找右区间

题目 给你一个区间数组 intervals &#xff0c;其中 intervals[i] [starti, endi] &#xff0c;且每个 starti 都 不同 。 区间 i 的 右侧区间 可以记作区间 j &#xff0c;并满足 startj > endi &#xff0c;且 startj 最小化 。注意 i 可能等于 j 。 返回一个由每个区…

P2089 烤鸡——Python解答

题目背景 猪猪 Hanke 得到了一只鸡。 题目描述 猪猪 Hanke 特别喜欢吃烤鸡&#xff08;本是同畜牲&#xff0c;相煎何太急&#xff01;&#xff09;Hanke 吃鸡很特别&#xff0c;为什么特别呢&#xff1f;因为他有 1010 种配料&#xff08;芥末、孜然等&#xff09;&#xf…

有关系型数据库的情况下,为什么还要使用NOSQL(非关系型数据库)?

1.NOSQL的相对灵活性 与关系型数据库相比&#xff0c;NOSQL数据库展现了更高的灵活性和扩展性优势。它无需预先设计固定的表结构&#xff0c;因此可以根据实际应用需求灵活地进行数据的存储和组织。 2.读写情况下的性能优势 关系型数据库注重数据的一致性&#xff0c;有时为…

某眼实时票房接口获取

某眼实时票房接口获取 前言解决方案1.找到veri.js2.找到signKey所在位置3.分析它所处的这个函数的内容4.index参数的获取5.signKey参数的获取运行结果关键代码另一种思路票房接口:https://piaofang.maoyan.com/dashboard-ajax https://piaofang.maoyan.com/dashboard 实时票房…

Docker实例

华子目录 docker实例1.为Ubuntu镜像添加ssh服务2.Docker安装mysql docker实例 1.为Ubuntu镜像添加ssh服务 (1)访问https://hub.docker.com&#xff0c;寻找合适的Ubuntu镜像 (2)拉取Ubuntu镜像 [rootserver ~]# docker pull ubuntu:latest latest: Pulling from library/ub…