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

news2024/12/23 5:36:51

文章目录

  • 如何通过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.coloradmin.cn/o/2114555.html

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

相关文章

MES系统如何支持企业进行数字化转型

MES系统&#xff08;Manufacturing Execution System&#xff0c;制造执行系统&#xff09;在企业数字化转型中扮演着至关重要的角色&#xff0c;它通过提供实时的生产数据、优化生产流程、提升质量管理水平、实现设备智能化管理以及促进企业内部协同和沟通等多种方式&#xff…

行政组织理论-第十二章:政府再造流程

章节章节汇总第一章&#xff1a;绪论第二章&#xff1a;行政组织的演变第三章&#xff1a;科层制行政组织理论第四章&#xff1a;人本主义组织理论第五章&#xff1a;网络型组织理论第六章&#xff1a;行政组织目标第七章&#xff1a;行政组织结构第八章&#xff1a;行政组织体…

MarkdownEditor 配置以及使用

MarkdownEditor 配置以及使用 MarkdownEditor是一款基于浏览器的 Markdown 编辑器&#xff0c;虽然他是独立软件&#xff0c;但该软件内嵌一个浏览器。功能非常简单实用、反应速度很快&#xff0c;号称是Markdown领域的NotePad&#xff08;记事本&#xff09;。 MarkdownEdit…

港科夜闻 | 叶玉如校长出席2024科技+新质生产力高峰论坛发表专题演讲,贡献国家科技强国战略...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、叶玉如校长出席“2024科技新质生产力高峰论坛”&#xff0c;做了题为“三个创新&#xff1a;培育和发展新质生产力、贡献国家科技强国战略”的主题演讲。该论坛于9月2日在香港召开。论坛围绕夯实基础科研、推动源头创新、…

【VUE】Vue 项目基本开发结构介绍

&#x1f4dd;个人主页&#x1f339;&#xff1a;个人主页 ⏩收录专栏⏪&#xff1a;VUE &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339;&#xff0c;让我们共同进步&#xff01; 在 Vue 开发中&#xff0c;了解 Vue 项目的基本结构是进行 Vue 开发的基础…

爬虫基础知识+豆瓣电影实战

什么是爬虫 简单来说&#xff0c;爬虫就是获取网页并提取和保存信息的自动化程序&#xff0c;爬虫能够自动请求网页&#xff0c;并将所需要的数据抓取下来。通过对抓取的数据进行处理&#xff0c;从而提取出有价值的信息进行存储使用。 为什么用Python做爬虫 首先您应该…

python 中使用tkinter构建一个图片的剪切器-附源码

由于项目需要&#xff0c;需要构建一个间的软件&#xff0c;方便查看图片的剪切的位置&#xff0c;并对其中的图像进行分析&#xff0c;实现如下的功能 简单的UI加载图片剪切图片显示剪切后的图片 针对图片的内容进行识别 图片质量分析 前端的具体代码如下&#xff0c; 有需…

5.8 切换保护模式(5)

1 首先测试 了&#xff0c; 之前的代码 是 没有问题的&#xff0c;确实会 停在 汇编处。 1 首先是 设置 除了 CS 之外的寄存器 进入 32为模式 //为了使除了 cs 之外的 段选择寄存器也进入 32位模式。mov $16, %ax // 16为数据段选择子mov %ax, %dsmov %ax, %ssmov %ax, %esmov…

axure动态面板

最近转管理岗了&#xff0c;作为项目负责人&#xff0c;需要常常与客户交流沟通&#xff0c;这时候画原型的能力就是不可或缺的本领之一了&#xff0c;关于axure可能很多it行业者都不是很陌生&#xff0c;简单的功能呢大家就自行去摸索&#xff0c;我们这次从动态面板开始讲起。…

C语言进阶版第8课—指针(2)

文章目录 1. 数组名的理解2. 指针访问数组3. 一维数组传参本质4. 冒泡排序5. 二级指针6. 指针数组7. 指针数组模拟二维数组 1. 数组名的理解 sizeof&#xff08;数组名&#xff09;— 这里的数组名代表整个数组&#xff0c;计算的也是整个数组的大小&数组名 — 这里的数组名…

adb devices找不到设备

重新启动ADB服务。在命令行窗口中输入adb kill-server&#xff0c;然后再输入adb start-server&#xff0c;重新启动ADB服务 再重启插入手机连入电脑的线&#xff0c;再次启动开发模式。 在在命令行窗口中输入adb version

【大数据】深入浅出Hadoop,干货满满

【大数据】深入浅出Hadoop 文章脉络 Hadoop HDFS MapReduce YARN Hadoop集群硬件架构 假设现在有一个PB级别的数据库表要处理。 在单机情况下&#xff0c;只能升级你的内存、磁盘、CPU&#xff0c;那么这台机器就会变成 “超算”&#xff0c;成本太高&#xff0c;商业公司肯…

Java基础知识回顾-匿名内部类

文章目录 知识学习实现案例第一步、父类定义方法第二步、子类中定义匿名内部类第三步、执行方法 最近在复习Java知识点的时候&#xff0c;在看匿名内部类&#xff0c;记录下来&#xff0c;方便备查。 知识学习 匿名内部类&#xff0c;即一种特殊的局部内部类&#xff0c;不需要…

java opencv no opencv_java490 in java.library.path

java使用opencv处理图片&#xff0c;idea运行程序&#xff0c;报错异常信息&#xff1a; Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java490 in java.library.path: /Users/carter/Library/Java/Extensions:/Library/Java/Extensions:…

Canvas Confetti - 免费开源的五彩纸屑飞舞特效的 JS 库,多用于在网页上实现欢乐庆祝的场景

今天看科技周刊看到的一个酷炫的动效库&#xff0c;使用简单&#xff0c;视觉效果很好&#xff0c;推荐给大家。 Canvas Confetti 是一个基于 JavaScript 的特效动画库&#xff0c;可以在网页界面上轻松地实现五彩纸屑飞舞的庆祝场景特效。这个特效库封装了几种酷炫的特效&…

Linux系统之实现dhcp功能(Implementation of DHCP Function in Linux System)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

tabBar设置底部菜单以及选项iconfont图标

1.tabBar设置底部菜单 在官网里面可以了解到tabBar组件的一些知识和注意点&#xff1a; 需要给页面设置一个底部导航的话可以在pages.json里面设置一个tabBar标签&#xff0c;在其里面设置pagePath和text属性。 可以看的pagePath是跳转的地址&#xff0c;text是下面导航的文字…

string详解

Golang详解string 文章目录 Golang详解stringGolang中为什么string是只读的&#xff1f;stirng和[]byte的转化原理[]byte转string一定需要内存拷贝吗&#xff1f;字符串拼接性能测试 Golang中为什么string是只读的&#xff1f; 在Go语言中&#xff0c;string其实就是一个结构体…

SSM项目使用AOP技术进行日志记录

本步骤只记录完成切面所需的必要代码 本人开发中遇到的问题&#xff1a; 切面一直切不进去&#xff0c;最后发现需要在springMVC的核心配置文件中中开启注解驱动才可以&#xff0c;只在spring的核心配置文件中开启是不会在web项目中生效的。 之后按照下面的代码进行配置&…

【Python篇】PyQt5 超详细教程——由入门到精通(中篇二)

文章目录 PyQt5超详细教程前言第7部分&#xff1a;生成图表与数据可视化7.1 matplotlib 与 PyQt5 的结合7.2 在 PyQt5 中嵌入 matplotlib 图表示例 1&#xff1a;嵌入简单的 matplotlib 图表代码详解&#xff1a; 7.3 动态生成图表示例 2&#xff1a;动态更新图表代码详解&…