前言直到有一天你会碰到线上奇奇怪怪的问题,如:
这类问题并不像一个空指针、数组越界这样明显好查,这时就需要刚才提到的内存模型、对象创建、线程等相关知识结合在一起来排查问题了。 正好这次借助之前的一次生产问题来聊聊如何排查和解决问题。 生产现象首先看看问题的背景吧: 我这其实是一个定时任务,在固定的时间会开启 N 个线程并发的从 Redis 中获取数据进行运算。 业务逻辑非常简单,但应用一般涉及到多线程之后再简单的事情都要小心对待。 果不其然这次就出问题了。 现象:原本只需要执行几分钟的任务执行了几个小时都没退出。翻遍了所有的日志都没找到异常。 于是便开始定位问题之路。 定位问题既然没办法直接从日志中发现异常,那就只能看看应用到底在干嘛了。 最常见的工具就是 JDK 自带的那一套。 这次我使用了 当然在 dump 之前是需要知道我应用的 pid 的,可以使用 当然如果知道关键字的话直接使用 拿到 如果应用简单不复杂,线程这些也比较少其实可以直接打开查看。 但复杂的应用导出来的日志文件也比较大还是建议用专业的分析工具。 我这里的日志比较少直接打开就可以了。 因为我清楚知道应用中开启的线程名称,所以直接根据线程名就可以在日志中找到相关的堆栈:
其实其他几个线程都和这里的堆栈类似,很明显的看出都是在做 Redis 连接。 于是我登录 Redis 查看了当前的连接数,发现已经非常高了。 这样 Redis 的响应自然也就变慢了。 接着利用 解决办法
既然找到了问题,那如何解决呢?
目前我们选择的是第一个方案,效果很明显。 本地模拟上文介绍的是线程相关问题,现在来分析下内存的问题。 以这个类为例: https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/oom/heap/HeapOOM.java 1public class HeapOOM { 启动参数如下:
为了更快的突出内存问题将堆的最大内存固定在 20M,同时在 JVM 出现 OOM 的时候自动 dump 内存到 执行之后果不其然出现了异常: 同时对应的内存 dump 文件也生成了。 内存分析这时就需要相应的工具进行分析了,最常用的自然就是 MAT 了。 我试了一个在线工具也不错(文件大了就不适合了): http:///index.jsp 上传刚才生成的内存文件之后: 因为是内存溢出,所以主要观察下大对象: 也有相应提示,这个很有可能就是内存溢出的对象,点进去之后: 看到这个堆栈其实就很明显了: 在向 ArrayList 中不停的写入数据时,会导致频繁的扩容也就是数组复制这些过程,最终达到 20M 的上限导致内存溢出了。 更多建议上文说过,一旦使用了多线程,那就要格外小心。 以下是一些日常建议:
总结线上问题定位需要综合技能,所以是需要一些基础技能。如线程、内存模型、Linux 等。 当然这些问题没有实操过都是纸上谈兵;如果第一次碰到线上问题,不要慌张,反而应该庆幸解决之后你又会习得一项技能。 |
|