Java 面试题:通过JProfile排查OOM问题 内存溢出与内存泄漏问题 --xunznux

文章目录

  • 如何通过JProfile排查OOM或内存泄漏问题
    • 1、启动工具观测程序执行状态
    • 2、使用默认设置采样
    • 3、查看memory,Run GC无效
    • 4、查看 Live Memory发现两个byte大数组存在
    • 5、通过快照查看堆中的内存使用情况
    • 6、找到Full GC无法清除的对象
    • 通过大对象列表定位内存泄漏问题
    • 怎么解决内存泄漏
  • 内存溢出和内存泄漏
    • 内存溢出
    • 内存泄漏

如何通过JProfile排查OOM或内存泄漏问题

先编写一个代码模拟内存泄漏:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @author XiuJun* @date 2024/9/7*/
public class OOMDemo {// 定义一个 ThreadLocal 变量,存储一个大对象(如 byte 数组)private static ThreadLocal<byte[]> threadLocal = new ThreadLocal<>();public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService executorService = Executors.newFixedThreadPool(2);for (int i = 0; i < 2; i++) {executorService.submit(() -> {try {// 为 ThreadLocal 设置一个大对象threadLocal.set(new byte[1024 * 1024 * 100]); // 10 MB 的数组System.out.println(Thread.currentThread().getName() + " 设置了大对象");// 模拟执行任务Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {// 如果不调用 remove,可能会导致内存泄漏// threadLocal.remove();}});}for (int i = 0; i < 3; i++) {executorService.submit(() -> {try {System.out.println(Thread.currentThread().getName() + " 线程复用了");// 模拟执行任务Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {// 如果不调用 remove,可能会导致内存泄漏// threadLocal.remove();}});}// 关闭线程池
//        executorService.shutdown();}
}

这里通过线程池,先通过两个线程执行两个任务,每个线程会有一个100MB的ThreadLocal变量。执行完之后,没有通过remove方法移除ThreadLocal变量,之后任务执行完,线程空闲然后被其他任务复用了线程。通过JProfile工具查看就可以发现两个byte数组还存在,并且无法被GC回收,因为他们还被Entry强引用,无法被标记为可回收。最后就会发生内存泄漏。

1、启动工具观测程序执行状态

在这里插入图片描述

2、使用默认设置采样

在这里插入图片描述

3、查看memory,Run GC无效

在这里插入图片描述

4、查看 Live Memory发现两个byte大数组存在

在这里插入图片描述

5、通过快照查看堆中的内存使用情况

在这里插入图片描述

6、找到Full GC无法清除的对象

在这里插入图片描述

通过大对象列表定位内存泄漏问题

在这里插入图片描述

怎么解决内存泄漏

到此,就可以发现是两个线程的ThreadLocal导致的内存泄漏问题。加上remove操作后,再次手动GC就可以发现两个byte数组会被清理掉,内存泄漏问题解决。

内存溢出和内存泄漏

解决OOM问题的重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。内存泄漏是存在着不健康的对象占用了有用的空间导致最终发生OOM,而内存溢出则是因为需要使用的对象所需内存大于堆内存,需要优化程序或者加大堆空间。

  • 内存泄漏就是有大量的引用指向某些对象,但是这些对象以后不会使用了,但是因为它们还和 GC ROOT 有关联,所以导致以后这些对象也不会被回收,这就是内存泄漏的问题。

  • 垃圾是指在运行程序中没有任何指针指向的对象,这个对象就是需要被回收的垃圾。如果不及时对内存中的垃圾进行清理,那么,这些垃圾对象所占的内存空间会一直保留到应用程序的结束,被保留的空间无法被其它对象使用,甚至可能导致内存溢出。

  • 如果是内存泄漏,可进一步通过工具(JProfile)查看泄漏对象到 GC Roots 的引用链。于是就能找到泄漏对象是通过怎样的路径与 GCRoots 相关联并导致垃圾收集器无法自动回收它们的。掌握了泄漏对象的类型信息,以及 GCRoots 引用链的信息,就可以比较准确地定位出泄漏代码的位置。

  • 如果不存在内存泄漏,换句话说就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx 与-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

内存溢出

javadoc 中对 outofMemoryError 的解释是,没有空闲内存,并且垃圾收集器也无法提供更多内存。
首先说没有空闲内存的情况:说明 Java 虚拟机的堆内存不够。原因有二:

  • Java 虚拟机的堆内存设置不够。
    • 比如:可能存在内存泄漏问题;也很有可能就是堆的大小不合理,比如我们要处理比较可观的数据量,但是没有显式指定 JVM 堆大小或者指定数值偏小。我们可以通过参数-Xms 、-Xmx 来调整。
  • 代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)
    • 对于老版本的 oracle JDK,因为永久代的大小是有限的,并且 JVM 对永久代垃圾回收(如,常量池回收、卸载不再需要的类型)非常不积极,所以当我们不断添加新类型的时候,永久代出现 OutOfMemoryError 也非常多见,尤其是在运行时存在大量动态类型生成的场合;类似 intern 字符串缓存占用太多空间,也会导致 OOM 问题。对应的异常信息,会标记出来和永久代相关:“java.lang.OutOfMemoryError:PermGen space"。
    • 随着元数据区的引入,方法区内存已经不再那么窘迫,所以相应的OOM 有所改观,出现 OOM,异常信息则变成了:“java.lang.OutofMemoryError:Metaspace"。直接内存不足,也会导致 OOM。

在抛出 OutofMemoryError 之前,通常垃圾收集器会被触发,尽其所能去清理出空间。
当然,也不是在任何情况下垃圾收集器都会被触发的。比如,我们去分配一个超大对象,类似一个超大数组超过堆的最大值,JVM 可以判断出垃圾收集并不能解决这个问题,所以直接抛出 OutofMemoryError。

内存泄漏

严格来说,只有对象不会再被程序用到了,但是 GC 又不能回收他们的情况,才叫内存泄漏。但实际情况很多时候一些不太好的实践(或疏忽)会导致对象的生命周期变得很长甚至导致 00M,也可以叫做宽泛意义上的“内存泄漏”。
尽管内存泄漏并不会立刻引起程序崩溃,但是一旦发生内存泄漏,程序中的可用内存就会被逐步蚕食,直至耗尽所有内存,最终出现 outofMemory 异常,导致程序崩溃。

实际应用中,我们可以通过定期去进行GC,然后查看GC后的内存是否在稳步增大,这个现象很有可能就是由于存在某些对象无法被回收导致的内存泄漏问题,需要进行堆转储后查看是哪些对象,进行下一步的分析,判断是不是需要使用的对象。

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

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

相关文章

【SpringBoot】电脑商城-12-订单功能

创建订单 1 订单-创建数据表 1.使用use命令先选中store数据库。 USE store;2.在store数据库中创建t_order和t_order_item数据表。 CREATE TABLE t_order (oid INT AUTO_INCREMENT COMMENT 订单id,uid INT NOT NULL COMMENT 用户id,recv_name VARCHAR(20) NOT NULL COMMENT …

Mac 上 YYDS 的自动切换输入法工具:好用到原地炸裂式起飞

有一种幸福的状态就是 任何时刻你都可以全力以赴 被打断、被终止也没有遗憾 因为你对结果没有那么期待 而且已经用尽全力了 当你深刻认识到你所做的事情 是多么好的时候 自然会产生一种想要分享出去 的心情 如今社会大部分工作都被电脑化了&#xff0c;在很多方面我们的…

第140天:内网安全-横向移动局域网ARP欺骗DNS劫持钓鱼中间人单双向

目录 案例一&#xff1a;局域网&工作组-ARP原理-断网限制-单向 案例二&#xff1a;局域网&工作组-ARP欺骗-劫持数据-双向 案例三&#xff1a;局域网&工作组-DNS 劫持-钓鱼渗透-双向 案例一&#xff1a;局域网&工作组-ARP原理-断网限制-单向 原理&#xff1…

数据库MySQL基础

目录 一、数据库的介绍 1.数据库概述 &#xff08;1&#xff09;数据的存储方式 &#xff08;2&#xff09;数据库 2.常见数据库排行榜 二、数据库的安装与卸载 1.数据库的安装 2.数据库的卸载 三、数据库服务的启动与登录 1.Windows 服务方式启动 &#xff08;1&…

Java反序列化漏洞-TemplatesImpl利用链分析

文章目录 一、前言二、正文1. 寻找利用链2. 构造POC2.1 生成字节码2.2 加载字节码1&#xff09;getTransletInstance2&#xff09;defineTransletClasses 2.3 创建实例 3. 完整POC 三、参考文章 一、前言 java.lang.ClassLoader#defineClass defineClass可以加载字节码&…

相机常见名词详解

本文主要参考超人视觉课程做的笔记&#xff0c;有讲解不太懂的&#xff0c;又做了详细的解释 1、物距&#xff1a;物体到镜片的距离&#xff1b; 2、像距&#xff1a;像到镜片的距离&#xff1b; 3、焦距&#xff1a;镜片到焦点的距离&#xff1b; (1)二倍焦距以外&#xff…

AF路由模式组网部署

实验拓扑 防火墙基本配置 接口配置 eth1 eth2 eth3 路由配置 地址转换配置 放通策略 1. 出口申请了主电信、备联通两条外网线路&#xff08;均为 50M 带宽&#xff09;。 2. 内网有 web 服务器linux 172.16.3.100运行 http 服务&#xff0c;内外网用户通过 出口路由器…

用PG Back Web轻松进行PostgreSQL备份

什么是 PG Back Web &#xff1f; PG Back Web &#x1f418; 使用用户友好的 Web 界面轻松进行 PostgreSQL 备份&#xff01;&#x1f310;&#x1f4be;。PG Back Web 不仅仅是另一个备份工具。借助 PG Back Web&#xff0c;用户可以通过受 PGP 加密保护的直观 Web 界面轻松安…

【redis】数据量庞大时的应对策略

文章目录 为什么数据量多了主机会崩分布式系统应用数据分离架构应用服务集群架构负载均衡器数据库读写分离 引入缓存冷热分离架构 分库分表微服务是什么代价优势 为什么数据量多了主机会崩 一台主机的硬件资源是有上限的&#xff0c;包括但不限于一下几种&#xff1a; CPU内存…

【Postgresql】地理空间数据的存储与查询,查询效率优化策略,数据类型与查询速度的影响

注&#xff1a;使用postgresql数据库会用到PostGIS 扩展。 一、安装PostGIS 扩展 在 PostgreSQL 中遇到错误 “type geography does not exist” 通常意味着你的 PostgreSQL 数据库还没有安装 PostGIS 扩展&#xff0c;或者 PostGIS 扩展没有被正确地安装在你的数据库中。geo…

我司使用了两年的高效日志打印工具,非常牛逼!

为了更方便地排查问题&#xff0c;电商交易系统的日志中需要记录用户id和订单id等字段。然而&#xff0c;每次打印日志都需要手动设置用户id&#xff0c;这一过程非常繁琐&#xff0c;需要想个办法优化下。 log.warn("user:{}, orderId:{} 订单提单成功",userId, or…

linux服务器之top命令详解

top&#xff1a;系统资源管理器 top命令类似于windows的任务管理器&#xff0c;可以查看内存、cpu、进程等信息(动态查看系统资源信息)在linux系统中常用top命令查看资源性能分析工具 一、参数释义&#xff1a; 第一行 系统时间和平均负载 top&#xff1a;名称22:12:46&#…

Spring Boot 部署方案!打包 + Shell 脚本详解

本篇和大家分享的是springboot打包并结合shell脚本命令部署&#xff0c;重点在分享一个shell程序启动工具&#xff0c;希望能便利工作&#xff1b; profiles指定不同环境的配置 maven-assembly-plugin打发布压缩包 分享shenniu_publish.sh程序启动工具 linux上使用shenniu_p…

一文梳理RAG(检索增强生成)的现状与挑战

一 RAG简介 大模型相较于过去的语言模型具备更加强大的能力&#xff0c;但在实际应用中&#xff0c;例如在准确性、知识更新速度和答案透明度方面&#xff0c;仍存在不少问题&#xff0c;比如典型的幻觉现象。因此&#xff0c;检索增强生成 (Retrieval-Augmented Generation, …

哪种超声波清洗机效果好?较好的超声波眼镜清洗机品牌推荐

作为一名拥有20年戴镜经验的眼镜爱好者&#xff0c;我深深体会到眼镜清洁的挑战&#xff1a;微小缝隙里的污垢难以触及&#xff0c;频繁的脏污让我苦于找不到清洁时机&#xff0c;而用力不当的擦拭方法更是可能对眼镜特别是镜片造成伤害&#xff0c;这确实让人感到苦恼&#xf…

Java专栏介绍

专栏导读 在当今这个技术飞速发展的时代&#xff0c;Java作为一门成熟且广泛应用的编程语言&#xff0c;一直是软件开发领域的中坚力量。本“Java技术”专栏旨在帮助读者深入理解Java编程语言的精髓&#xff0c;掌握其核心概念与高级特性&#xff0c;并通过实战案例提升编程技…

字符编码转换

文章目录 1. 背景2. 解决方案3. 编码转换实现3.1 shell实现3.2 python实现3.3 开源工具实现 4. 常见中文字符编码介绍4.1 字符编码解决什么问题4.2 常见的中文字符编码4.3 常见中文字符编码关系4.4 unicide字符集与utf-8 1. 背景 在团队合作开发中&#xff0c;经常发现组员的代…

Redis安装步骤——离线安装与在线安装详解

Linux环境下Redis的离线安装与在线安装详细步骤 环境信息一、离线安装1、安装环境2、下载redis安装包3、上传到服务器并解压4、编译redis5、安装redis6、配置redis&#xff08;基础配置&#xff09;7、启动redis8、本机访问redis9、远程访问redis 二、在线安装1、更新yum源2、安…

k8s 高级调度

搞懂Kubernetes调度 K8S调度器Kube-schduler的主要作用是将新创建的Pod调度到集群中的合适节点上运行。kube-scheduler的调度算法非常灵活&#xff0c;可以根据不同的需求进行自定义配置&#xff0c;比如资源限制、亲和性和反亲和性等。 kube-scheduler的工作原理如下&#x…

基于SpringBoot+Vue+MySQL的宿舍维修管理系统

系统展示 前台界面 管理员界面 维修员界面 学生界面 系统背景 在当今高校后勤管理的日益精细化与智能化背景下&#xff0c;宿舍维修管理系统作为提升校园生活品质、优化资源配置的关键环节&#xff0c;其重要性日益凸显。随着学生规模的扩大及住宿条件的不断提升&#xff0c;宿…