马士兵—JVM—内存溢出—1.线上OOM(内存溢出)问题排查——亲测

1. 模拟线上oom问题

1.1 代码

@GetMapping("/addList")
    public void addList(){
        List list = new ArrayList();
        while (true){
            String a = "aaaaa"+new Date();
            list.add(a);
            System.out.println(a);
        }
    }

2. 线上环境启动,并配置打印gc日志

启动脚本

设置内存小一点 都为20m。

java  -Xms20m -Xmx20m -Xloggc:./gc.log -jar test.jar >> test.log 2>&1 &

3. 调用死循环代码

3.1 控制台报错日志

在这里插入图片描述

3.2 gc日志

可以看到全是full gc
在这里插入图片描述

4. 问题排查方法

4.1 TOP命令查看cpu

此时的cpu已经飙升到了80%多了
在这里插入图片描述

4.1 jps

查看当前的java程序信息,前面是进程号。
如果显示的是jar。没有显示项目的名称,是因为启动的时候没事使用包的绝对路径。自己改一下。
在这里插入图片描述

4.2 jinfo -进程号

5. JConsule链接远程服务器

5.1 启动脚本可以使用如下的。不然可能链接不上

注意hostname的ip地址要和本机地址一样

nohup java  \
-Djava.rmi.server.hostname=192.168.17.129 \
-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.port=1099 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-XX:+PrintGC -Xms80M -Xmx80M \
-jar test.jar > test.log 2>&1 &

5.2 登录页面

在这里插入图片描述
这里的端口号,和上面启动脚本的端口号保持一直,不然等不上去。

5.3 登录成功

选择不安全链接
在这里插入图片描述

6. jvisualvm

6.1 登录

点击文件。选择添加jmx连接。然后输入和上面jconsule一样的地址。就可以登录。
在这里插入图片描述

6.2 登录成功页面

可以看到一些启动参数信息。
在这里插入图片描述

7. 线上真实环境

首先为什么不用图形化界面。首先如果你需要实时监控。这样的话那就需要一直的启动一个程序jmxremote来一直监听这服务。所以比较消耗性能。这样是不可能的。

7.1 jmap 获取相关信息(重要)

获取内存占用情况的前二十行。

 jmap -histo 8995 | head -20

可以看出占用最多的是char[]。
在这里插入图片描述

自动生产堆文件,当内存溢出的时候。

-XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError

启动脚本,在第一次oom的时候生成一个dump文件,他的后缀不是dump的。注意可能只在第一次oom的时候生成文件。

nohup java  \
-Djava.rmi.server.hostname=192.168.17.129 \
-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.port=1099 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError \
-Xms80M -Xmx80M \
-jar test.jar > test.log 2>&1 &

7.2 jmap的相关命令

7.2.1 查看整个JVM内存状态

jmap -heap [pid]
要注意的是在使用CMS GC 情况下,jmap -heap的执行有可能会导致JAVA 进程挂起

7.2.2 查看JVM堆中对象详细占用情况(jmap -histo)(极力推荐)在线定位问题

jmap -histo [pid]

jmap -histo [pid] | head -20 (前20行)
基本就可以定位到问题,我们可以看到是OomController这个类的,有关Person的相关问题。
在这里插入图片描述

7.2.3 导出整个JVM 中内存信息Dump文件(jmap -dump)

一般在线系统不要这么干。

缺点和方法:

  1. jmap执行期间会对进程产生很大影响,甚至卡顿。
  2. 线上是不能执行jmap。
  3. 设定参数HeapDump ,OOM的时候会自动产生堆文件。
  4. 面试最佳答案:我们很多服务器备份,停掉这台服务器,然后将这台服务器隔离开。然后用jmap导出,导出之后在观察,面试官就不会再有问题了
    jmap -dump:format=b,file=文件名 [pid]
jmap -dump:format=b,file=oom.dump 10922

在这里插入图片描述

8. 使用jvisualvm分析dump文件

在文件按钮选择转入->文件类型选择堆->选择dump文件
在这里插入图片描述
转入之后生产的文件。导入分析页面。

8.1 装入好多字符串oom

  @GetMapping("/addList")
    public void addList(){
        List list = new ArrayList();
        while (true){
            String a = "aaaaa"+new Date();
            list.add(a);
            System.out.println(a);
        }
    }

在这里插入图片描述

8.2 装入好多对象错误

 @GetMapping("/addPerson")
    public void addPerson(){
        List list = new ArrayList();
        while (true){
            list.add(new Person());
            System.out.println('p');
        }
    }

在这里插入图片描述

8.3 查找最大的对象(很重要)

一下就可以知道是arrayList数组太大。
在这里插入图片描述

面试

案例一:

发现不知道哪位同事在设置tomcat的http-header-size参数的时候设置的过大。

server.port=9898
server.max-http-header-szie=10000000

通过jmap查询对象的时候,发现一定会有http对象较大。这样比较容易定位是这个问题。

案例二(比较牛逼)

Distuptor有个可以设置链的长度,如果过大,然后对象大,消费完不主动释放,会溢出

案例三

线程池不当运用产生OOM问题
不断的往List里加对象(实在太LOW)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值