《JVM第10课》内存溢出(OOM)排查过程

server/2024/11/14 1:17:34/

文章目录

    • 常用命令
      • 1. jps
      • 2. jconsole
      • 3. jstat
      • 4. jmap
    • 工具
      • 1.jvisualvm

排查OOM的方法其实很简单很简单。

  1. 如果能找到拋OOM的日志,可以在日志里看到是哪一行抛出的OOM异常。
  2. 如果找不到日志,那么处理方式是导出Java进程的内存快照,然后用工具查看OOM日志。
  3. 如果打印OOM日志的行不是导致OOM的罪魁祸首(因为也许是别的地方把内存占完了,刚好此处要申请内存,就抛OOM了),那就通过工具查看哪些对象占用了大量内存未释放,进而找到这些对象的所在的类。

在学习如何排查OOM之前,先来学习几个常用的命令,它们对于分析内存、线程、垃圾收集有着很好的帮助。如果不想浪费时间也可直接跳到“工具”目录。

常用命令

1. jps

jps 是 JDK 自带的命令行工具,用于查看 Java 进程。

我们都知道 Linux 中 ps 命令是用来查看进程的,jps 相当于是 java ps,是只查看 Java 进程的命令,在Windows和Linux上都可以。

例如我们写一个main方法:

java">public class Test1 {public static void main(String[] args) throws InterruptedException {while (true) {Thread.sleep(1000L);System.out.println("hello world");}}
}

使用jps命令查看进程号:

在这里插入图片描述

2. jconsole

jconsole 是 JDK 自带的一个图形化监控工具。

只能在Windows上使用,在Linux上一般打不开除非有图形界面库。

用它可以连接到正在运行的 Java 应用程序,并监视其 CPU 使用率、内存使用情况、线程状态、有无死锁、类加载等。jconsole 对于实时监控 Java 应用程序的健康状况和进行性能调优非常有用。

我们直接在控制台输入 jconsole 回车便可打开监控工具。

step1: 输入控制台输入jconsole,回车,打开如下界面。

在这里插入图片描述

step2: 选择本地进程,如我这里选的是刚刚启动的Test1,然后选择“不安全的连接”。

在这里插入图片描述

然后就能非常直观的监控 CPU、内存、线程、类的状态啦~,如图:

在这里插入图片描述

在“线程”tab页,还可以非常方便的检测当前进程有无死锁状态的线程,这也是 jconsole 最常用的功能之一。如下图:

在这里插入图片描述

也可以使用jconsole连接远程的Java进程,但是一般不这么用,不做过多讲解。

3. jstat

jstat 相当于是 jconsole 的命令版,jconsole 是 jstat 的可视化版。

jstat 也是 JDK 自带的命令行工具,用于监控 Java 程序的垃圾收集、类加载、JIT编译等方面的信息。

常用命令:

jstat -class 查看类加载和卸载情况

jstat -compiler 查看JIT编译器的编译情况

使用方式见下图:

在这里插入图片描述

上面两个命令我们一般也用不到,最常用的命令还是 jstat -gcutil

jstat -gcutil 命令用于查看垃圾收集情况,包括新生代和老年代的垃圾收集信息。

在这里插入图片描述

解释图中命令:jstat -gc 是查看垃圾收集情况,1204是进程号,1000是每1秒打印一次,5是一共打印5次。这里的值是百分比,S1区被占用了26.78%,Eden区被占用了47.65%。

如果不想查看百分百而查看具体的值,可使用 jstat -gc 命令:

在这里插入图片描述

4. jmap

jmap 是 JDK 自带的一个命令行工具,主要用于打印出 Java 进程的内存快照,包括堆内存的详细信息、垃圾回收器信息等。它对于分析和诊断内存泄漏或需要优化内存使用的情况下非常有用。

使用方式:

jmap -dump:file=<文件名> <进程ID>

使用示例:

我们改造一下测试用例,让线程创建很多不能被回收的静态 Integer 对象并且让线程保持运行状态。如下

java">public class Test1 {static List<Integer> list = new ArrayList<>();public static void main(String[] args) {for (int i = 0; i < 1000000; i++) {list.add(i+1);}while (true) {}}
}

导出内存快照,如下:

在这里插入图片描述

然后就会生成一个 d.hprof 文件,接下来就可以用可视化工具检测内存状态啦~

其实,为了在发生OOM时及时导出快照信息,我们可以在 Java 应用启动时加上参数,让它在发生OOM时自动dump内存快照。参数如下

  • -XX:+HeapDumpOnOutOfMemoryError: 当 JVM 抛出 OOM 时,自动导出内存快照。
  • -XX:HeapDumpPath=<路径>: 指定快照文件的保存路径。如果没有指定这个参数,默认情况下,堆转储文件会被写入到工作目录下,文件名为 java_pid<进程id>.hprof。

工具

工具有很多,比如 jvisualvm、JProfile、Eclipse Memory Analyzer等等,各有千秋。我们这里只演示jvisualvm的用法。

我们先创建一段代码,让它抛出OOM异常并自动导出内存快照:

java">package com.fanren;import java.util.ArrayList;
import java.util.List;public class Test1 {static List<Integer> list = new ArrayList<>();public static void main(String[] args) {for (int i = 0; i < 1000000; i++) {list.add(i+1);}}
}

然后配置启动类,配置堆内存为10m并且发生OOM时自动导出内存快照:

在这里插入图片描述

接着运行就会报错:

在这里插入图片描述

已经发生OOM异常并且导出了 java_pid25104.hprof 文件。

接下来我们就可以在工具中使用 java_pid25104.hprof 文件排查OOM的原因了。

1.jvisualvm

jvisualvm在JDK 6 Update 7版本后作为标准工具被引入,也就是说 jvisualvm 是 JDK 自带的,省的下载了。

我们在控制台输入 jvisualvm 即可打开该工具。

在这里插入图片描述

如上图,进来后如果本地有正在运行的 Java 进程,可以监控此进程,双击打开可以看到右侧也有类似于 jconsole 的监控界面。也可以在此界面执行垃圾回收或是导出(dump)当前堆的快照,非常方便。

jvisualvm 不仅可以监控正在运行的进程内存状况,也可以导入内存快照。只需点击左上角的“装入快照”,我们把刚刚导出的 java_pid25104.hprof 给装入进来后如下图:

在这里插入图片描述

“概要”视图里已经提示了发生OOM的线程,点击之后就可以看到报错的行号:

在这里插入图片描述

可以发现正是我们的问题代码所在的行。

如果通过报错行号找到的不是导致OOM的罪魁祸首,那么可以点击“类”视图:

在这里插入图片描述

“类”视图里按照内存大小倒序后可以看到,Integer 类型对象占用了最多的空间,我们双击此行进入到“实例数”视图。如下:

在这里插入图片描述

在这个视图里选中一个对象实例,就可以在右侧“引用”模块查看到引用该对象的类是 Test1。

这样的话就可以得出结论:内存溢出是 Test1 类里面的 Integer 对象过多导致的。

于是我们就可以排查代码写得是不是有问题了。


http://www.ppmy.cn/server/141723.html

相关文章

Axure安装步骤及免费替代方案

Axure作为一款强大的原型设计工具&#xff0c;因其丰富的功能而受到设计师的青睐。它包括动态面板、复杂表格编辑、协同设计和高保真原型设计等&#xff0c;这些功能可以简化复杂的设计流程&#xff0c;提高团队效率。本文将介绍Axure的安装方法&#xff0c;并探索一款新兴的Ax…

JavaScript中的二叉树排序你了解吗?

写在前面 在计算机科学中&#xff0c;二叉树是一种常见的数据结构&#xff0c;用于存储和组织数据。二叉树排序&#xff08;Binary Tree Sort&#xff09;是一种基于二叉搜索树的排序算法。它的基本思想是将待排序的元素插入到二叉搜索树中&#xff0c;然后通过中序遍历二叉搜…

SobarQube实现PDF报告导出

文章目录 前言一、插件配置二、使用步骤1.新生成一个Token2.将拷贝的Token加到上文中执行的命令中3.查看报告 三、友情提示总结 前言 这篇博文是承接此文 .Net项目在Windows中使用sonarqube进行代码质量扫描的详细操作配置 描述如何导出PDF报告 众所周知&#xff0c;导出PDF功…

软件设计师-计算机体系结构分类

计算机体系结构分类 Flynn分类法 根据不同的指令流数据流组织方式分类单指令流但数据流SISD,单处理器系统单指令多数据流SIMD&#xff0c;单指令流多数据流是一种采用一个控制器来控制多个处理器&#xff0c;同时对一组数据&#xff08;又称“数据矢量”&#xff09;中的每一…

python数据写入excel文件

主要思路&#xff1a;数据 转DataFrame后写入excel文件 一、数据格式为字典形式1 k e &#xff0c; v [‘1’, ‘e’, 0.83, 437, 0.6, 0.8, 0.9, ‘好’] 1、这种方法使用了 from_dict 方法&#xff0c;指定了 orient‘index’ 表示使用字典的键作为行索引&#xff0c;然…

探索 Python 图像处理的瑞士军刀:Pillow 库

文章目录 探索 Python 图像处理的瑞士军刀&#xff1a;Pillow 库第一部分&#xff1a;背景介绍第二部分&#xff1a;Pillow库是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;简单的库函数使用方法第五部分&#xff1a;结合场景使用库第…

LeetCode【0006】Z字形变换

本文目录 1 中文题目2 求解思路2.1 基础解法&#xff1a;模拟法2.2 优化解法&#xff1a;数学规律法2.3 最优解法&#xff1a;字符串拼接法 3 题目总结 1 中文题目 将一个给定字符串 s 根据给定的行数 numRows &#xff0c;以从上往下、从左到右进行 Z 字形排列。 比如输入字符…

golang分布式缓存项目 Day6 防止缓存击穿

该项目原作者&#xff1a;https://github.com/geektutu/7days-golang。本文旨在记录本人做该项目时的一些疑惑解答以及部分的测试样例以便于本人复习。 1 缓存雪崩、缓存击穿与缓存穿透 概念解析&#xff1a; 缓存雪崩&#xff1a;缓存在同一时刻全部失效&#xff0c;造成瞬…