文章目录
前置知识
内存泄漏(Memory Leak)
内存泄漏是指程序中动态分配的内存由于某种原因(如引用未被正确释放)无法被系统回收,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。Java 通过垃圾回收器(Garbage Collector)来自动管理内存,但在某些情况下,如果程序员错误地持有对象引用(如长生命周期的对象引用了短生命周期的对象),垃圾回收器可能无法回收这些对象,从而导致内存泄漏
内存溢出异常(OutOfMemoryError):
当Java虚拟机(JVM)中的内存不足以满足对象的内存分配请求时,就会抛出 OutOfMemoryError。堆内存溢出是最常见的 OutOfMemoryError,通常由于创建了大量的 Java 对象,并且垃圾回收器无法回收它们来释放内存空间
打比方像 static List 这样的对象,程序可能不断往 List 中 add,它又没有办法失去引用造成内存泄漏
像线上服务(流量小的)如果是某个时间,内存使用率略微升高,且后续平缓不掉下来,一般说明线上服务运行到了 static,是正常现象
某个地方对象创建生成了。如果是流量大的服务,可能会有启动服务时候有内存使用很缓慢上涨的过程,然后最后趋于平稳,也是正常现象
使用到的工具
都是 jdk 自带的:
- 关键:jmap
- jps
- jstat
- jstack
linux 基础命令
本地工具 jvisualvm 或者 jprofiler 来排查 dump 文件分析内存泄漏原因
写在前面
你的线上服务某时候开始内存陡增,这个时候你很着急,该怎么办?
着急的排查过程
如果线上服务非常紧急,请参照以下步骤处理
- 告警后进入服务器
- 先查看 java 服务的进程号
- jmap dump 转储关键信息(好以后排查解决)
- 可选:jmap 临时看下哪些对象占用大
- 服务重启/回滚
- 后续本地用 jvisualvm/jprofiler 等工具来分析 dump 文件
不着急的排查过程
如果是无关紧要的服务,一点也不紧急,可以慢慢查看排查
- 告警后进入服务器
- 查看 java 服务进程号
- 看下 jvm 中当前资源使用情况
- 看下 java 服务该进程中各线程执行的内容情况
- jmap dump 转储关键信息
- jmap 查看哪些对象占用内存大
- 服务重启/回滚
- 后续用 jvisualvm/jprofiler 等工具来分析 dump 文件
发现问题
由于线上服务配置了内存过阈值的告警或者内存快速增加的告警,突然收到大量告警
看了一下服务器线上内存变化情况,发现上线后内存一直在快速增加
于是登录服务器查看…
排查流程
查看 java 服务进程号(必)
ps 命令查看进程号
ps -ef | grep java
或者:
jps(jvm process status)命令查看 jvm 启动的进程号是多少
# jps 用来看 jvm 启动的 java 进程
# jps 是 jvm 提供的进程状态工具,一般下载的 jdk 的 bin 中。主要作用是列出当前系统中由 JVM 启动的所有进程号及其主要类名
jps -l
大概看下 jvm 中资源使用状况
情况一:如果当前内存在不断的增加
jstat(jvm status)命令查看 JVM 当前的资源使用情况和性能统计信息
# jstat 是 jdk 包中自带的命令
# 表示每 2s 输出一行当前状况,输出 10 次结束
jstat -gc [pid] 2000 10
# util 表示百分比展现
jstat -gcutil [pid] 2000 10
- FGC 表示 full gc(jvm 从启动到采样时候进行 full 垃圾回收)的次数,老年代空间不足时候触发 full gc。在大对象分配时,或者大量循环里头不断进行对象分配,内存泄漏等会触发 full gc
- FGCT 表示从应用程序启动到采样时Full垃圾回收消耗的总时间(秒)
如果观察到 FGC
不断在增加,有可能是内存泄漏,也有可能是程序在频繁的大对象的分配
情况二:历史某个时间内存陡增,然后保持高值
可能是某个时间服务调用,然后内存泄漏
查看该进程中线程执行的内容
展现某个指定 pid 中所有线程情况(cpu,内存),第一列展现是线程不是进程号
# 展现某个 pid 中所有线程情况
top -p [pid