inputstreamreader未关闭会导致oom_java之OOM排查

1.引子

今天聊一下OOM的问题。OOM就是Out Of Memory。前几天,线上出现过一次,频繁的full GC的问题。今天就简单记录一下排查的步骤。

2.模拟

在这只能模拟OOM。很简单,就是一个集合,写个循环向里面添加对象。这个方法:startThread2

import java.util.ArrayList;import java.util.List;class Test {    public static void main(String[] args) {        if (args.length == 0) {            System.out.println("运行的时候请输入参:1 or 2");            return;        }        if (args[0].equalsIgnoreCase("1")) {            startThread1();        }        if (args[0].equalsIgnoreCase("2")) {            startThread2();        }    }    public static void startThread1() {        Thread thread = new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    String a = new String("deadThread");//System.out.println(a);                }            }        });        thread.setName("deadThread");        thread.start();    }    public static void startThread2() {        Thread thread = new Thread(new Runnable() {            @Override            public void run() {                List list = new ArrayList<>();                while (true) {                    String a1 = new String("OOMThread");                    list.add(a1);                }            }        });        thread.setName("OOMThread");        thread.start();    }}

3.编译运行

javac test.java
f180cb34c8c721ef1609f8b24e88d8f3.png

javac test.java

java -Xms10m -Xmx10m -XX:+PrintGC -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ Test 2
cd5e5d9f780afb2700ccf2a10b2fd307.png

注:

-Xms10m -Xmx10m 初始堆大小和最大堆大小。 这里是模拟,所以设置小一点

-XX:+PrintGC -XX:+PrintGCDetails 打印一下GC的日志

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ 当发送OOM的时候,自动保存Dump文件。后面那个是报错的路径,如果没有则,在当前目录下。

已运行会一直打gc日志,因为死循环在添加对象,并且对象还没法回收。

一会就会内存溢出,如下图

c39209c6b986fe9d7bfa65881df09775.png

4分析dump文件

发生OOM了。接着就是要分析一下这个dump文件了。分析的工具有很多,这里使用mat和jvisualvm分别分析一下,其实都差不多。

fde2b5c89bf7c5be644abf206245df06.png

首先,从服务器下载到本地。然后使用工具就行分析。

1.首先使用MAT分析:

打开mat,导入hprof文件。(注:如果hprof文件特别的大,需要调整一下mat的内存参数。防止内存溢出,打不开文件)

6f21f1699ecc7294f0c5f9eb4de8dfaa.png

mat

323237333244f611542a31274fa773ab.png
fa2eabad524a8c2355e16b5eb631d7f8.png
158b78004453501d8930504d601d8b70.png

我们可以看到mat已经帮我们分析到了一个错误:

2e5ea5376eee45b1997d4671a28c9073.png

点击details详情。会发现:

线程 OOMThread中一个ArrayList占了98.12%,而它里面放的是String对象。

3ce45c26a9f46be6e69500711601818d.png

注:这里面有两个比较难理解的名词(我理解的不一定完全对。大家可以自行百度一下):

1.shallow heap:shallow:浅的,我理解就是:这个对象实际占用的堆大小

2.retained heap:retained:保留的,这个有点难理解了:简单的话,就是它和它引用的对象(这里的引用对象没有被其他的对象引用)的占用堆的大小。(不知道理解的对不对。)如下图:arrayList中shallow是24,retained是9057600.以为我newString的都放到list中去了。

8116b729eb3db0838b79321f82ce3bc1.png

初步怀疑是ArrayList中对象过多,一直有引用,没有被gc回收导致。然后看一下抛出OOM的异常的地方。发现有对应的ArrayList。它有一个循环在一直添加String对象。

2.使用jvisualvm.exe

打开jvisualvm.exe,导入hprof文件。

4ee7175c07b057b8389599a09484ec30.png

在出现 OutOfMemoryError 异常错误时进行了堆转储导致 OutOfMemoryError 异常错误的线程: OOMThread

f5fd5e45ad7901a1ed6d5959273ec5d3.png

点击:OOMThread

35e9ee559ac3752e3dd36ae4c549d3db.png

显示是在什么地方发生的OOM,然后点击 红框的地方。

b67e6dd849485acc2c41288160d5dbb8.png

我们可以发现:arrayList的size大小为:317374. 猜测是arrayList结合中对象太多。由此可以去查对应的代码逻辑判断。

还可以点击类:会显示对象的个数和占比。会发现string对象,有318309个实例,占所有实例中99.1%,大小是8912652,占用了堆74.2%的空间

25dadd5dfedfa667b79674bcde310983.png

注:实际生产中情况,比这个要复杂,不过大概分析过程就是这样。其实频繁的fullgc也可以导出dump文件去分析。是不是有内存泄漏的地方。当然,一般大公司会有相应的监控系统,在堆空间超过某个阈值就会报警,这个时候,可以将这台机器从vip摘除或者(healthcheck先摘除了)这样Nginx就打不过来,就不会有用户的请求过来了。然后使用jmap导出dump文件分析。这个以后有时间再讲。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值