java线上问题排查之内存占用大解决步骤

 更新时间:2026年01月11日 11:44:22   作者:讓丄帝愛伱  
线上的问题在通常有一些预警,比如CPU被打满,网络达到顶峰等等问题,这篇文章主要介绍了java线上问题排查之内存占用大解决步骤,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、快速排查流程

二、详细排查步骤与命令

步骤1:快速定位问题进程

# 1. 查看系统整体内存使用
free -h
# 查看系统整体内存
free -h && echo "---" && top -bn1 | head -10
top -p <java_pid>

# 2. 查找Java进程内存排名
ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem | head -20
# 定位Java进程内存排名
ps -eo pid,ppid,cmd,%mem,rss --sort=-rss | head -15
# 查看Java进程列表
jps -mlv | grep -v Jps
# 或者使用更专业的工具
nmon -s1 -c10

# 3. 确认Java进程基本信息
jps -mlv
jcmd -l

步骤2:分析JVM内存分布

# 1. 查看堆内存详细分布
jhsdb jmap --heap --pid <pid>
jhsdb jmap --heap --pid $PID 2>/dev/null || jmap -heap $PID
# 2. 实时监控GC和内存使用
jstat -gcutil <pid> 1000 10
jstat -gccapacity <pid> 1000 5

# 3. 查看内存各区域使用详情
jcmd <pid> VM.native_memory summary scale=MB
jcmd $PID VM.native_memory summary scale=MB

# 检查大对象分布
jmap -histo:live $PID | sort -k3 -nr | head -30 > large_objects.txt

关键指标解读:

  • OU(Old Utilization):老年代使用率 >80% 需关注
  • MU(Metaspace Utilization):元空间使用率
  • CCS(Compressed Class Space):压缩类空间

步骤3:生成和分析堆转储

# 1. 生成堆转储文件(生产环境谨慎使用)
jmap -dump:live,format=b,file=heap_dump.hprof <pid>

# 2. 如果jmap不可用,使用jcmd(推荐)
jcmd <pid> GC.heap_dump filename=heap_dump.hprof
jcmd $PID GC.heap_dump filename=heap_$(date +%Y%m%d_%H%M%S).hprof

# 3. 仅统计对象数量(不影响服务)
jmap -histo:live <pid> | head -50 > object_histo.txt
# 仅生成直方图(生产环境安全)
jmap -histo $PID > object_histogram.tx

步骤4:分析堆转储文件

使用Eclipse MAT分析

# 下载MAT:https://www.eclipse.org/mat/
# 分析步骤:
1. File → Open Heap Dump
2. 查看Leak Suspects Report
3. 分析Dominator Tree
4. 查看重复字符串/集合大小

使用命令行快速分析

# 分析大对象
jhat heap_dump.hprof
# 访问 http://localhost:7000 查看分析结果

# 或者使用jHiccup
java -jar jHiccup.jar -p <pid>

步骤5:检查非堆内存

# 1. 检查元空间使用
jstat -gcmetacapacity <pid>

# 2. 检查线程数量
ps -eLf | grep <pid> | wc -l
jstack <pid> | grep "java.lang.Thread.State" | wc -l
jstack $PID | grep "java.lang.Thread.State" | sort | uniq -c > thread_states.txt

# 3. 检查直接内存
jcmd <pid> VM.native_memory detail | grep -A10 "Internal"
# 类加载统计
jcmd $PID VM.classloader_stats 2>/dev/null

# 4. 检查代码缓存
jstat -gccapacity <pid> | grep -i code

三、具体场景排查命令

场景1:堆内存泄漏排查

# 1. 实时监控对象创建
jstat -gcutil <pid> 1s

# 2. 跟踪GC日志(如果已开启)
tail -f /path/to/gc.log
# 实时查看GC情况
tail -f /path/to/gc.log | grep -E "Full GC|GC.*Pause"
# 使用分析工具(需要下载gcviewer)
java -jar gcviewer.jar /path/to/gc.log

# 3. 检查大对象
jmap -histo <pid> | sort -k3 -nr | head -20

# 4. 检查Finalizer队列
jcmd <pid> GC.finalizer_info

场景2:元空间溢出排查

# 1. 监控元空间增长
while true; do jstat -gcmetacapacity <pid>; sleep 2; done

# 2. 检查类加载器
jcmd <pid> VM.classloader_stats

# 3. 检查加载的类数量
jmap -clstats <pid>

# 4. 查找重复类
java -jar jarpath/classloader-analyzer.jar --pid <pid>

场景3:线程内存泄漏排查

# 1. 生成线程转储
jstack <pid> > thread_dump.txt

# 2. 统计线程状态
grep "java.lang.Thread.State" thread_dump.txt | sort | uniq -c

# 3. 检查线程栈大小
jinfo <pid> | grep -i stack

# 4. 分析线程创建轨迹(如果有Arthas)
thread -n 10

场景4:直接内存泄漏排查

# 1. 检查NIO直接内存
jcmd <pid> VM.native_memory summary | grep -A5 "Native Memory Tracking"

# 2. 监控堆外内存使用
pmap -x <pid> | sort -k3 -nr | head -10

# 3. 如果怀疑Netty等框架的内存泄漏
# 添加JVM参数:-XX:MaxDirectMemorySize=512m

四、使用Arthas进行在线诊断

# 安装并启动Arthas
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

# 内存诊断命令
dashboard                    # 整体监控面板
memory                       # 内存详情
heapdump --live /tmp/heap.hprof  # 在线堆转储

# 类加载监控
classloader -t              # 类加载器树
sc -d <ClassName>           # 查看类详情

# 方法级监控
monitor -c 5 com.example.Service methodName  # 方法执行统计
watch com.example.Service methodName "{params,returnObj}" -x 3  # 观察方法参数

五、容器环境特殊排查

# 1. 进入容器
docker exec -it <container_id> /bin/bash

# 2. 检查容器内存限制
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
cat /sys/fs/cgroup/memory/memory.usage_in_bytes

# 3. 调整JVM内存参数(如果设置不合理)
# 在启动参数中添加:
-XX:+UseContainerSupport
-XX:MaxRAMPercentage=75.0

# 4. 检查OOM Killer日志
dmesg | grep -i "killed process"
grep -i "oom" /var/log/messages

六、自动化监控脚本

内存监控脚本

#!/bin/bash
PID=$1
LOG_FILE="memory_monitor_${PID}.log"

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    # 收集内存指标
    HEAP_INFO=$(jstat -gcutil $PID 2>/dev/null | tail -1)
    THREAD_COUNT=$(ps -eLf | grep $PID | wc -l)
    
    echo "$TIMESTAMP | $HEAP_INFO | Threads: $THREAD_COUNT" >> $LOG_FILE
    sleep 30
done

快速排查一键脚本

#!/bin/bash
PID=$1
echo "=== 内存问题快速排查 ==="
echo "1. 进程信息:"
jps -mlv | grep $PID

echo -e "\n2. 内存分布:"
jstat -gcutil $PID

echo -e "\n3. 对象统计:"
jmap -histo $PID | head -30

echo -e "\n4. 线程统计:"
jstack $PID | grep "java.lang.Thread.State" | sort | uniq -c

七、常见问题模式与解决方案

模式1:缓存无限增长

症状: Old区持续增长,Full GC后很快又满
解决:

  • 检查缓存失效策略
  • 添加缓存大小限制
  • 使用WeakReference/SoftReference

模式2:资源未关闭

症状: 直接内存或文件描述符泄漏
解决:

  • 使用try-with-resources
  • 检查数据库连接池配置
  • 监控文件描述符数量

模式3:类加载器泄漏

症状: 元空间持续增长,频繁Full GC
解决:

  • 检查热部署/动态类生成
  • 分析类加载器引用链
  • 重启应用服务

模式4:大对象分配

症状: 年轻代GC频繁,对象直接进入老年代
解决:

  • 调整-XX:PretenureSizeThreshold
  • 优化大对象使用模式
  • 增加年轻代大小

根据症状快速定位问题

症状可能原因排查命令
Old区持续增长内存泄漏、缓存问题jmap -histo:live, MAT分析
频繁Full GC内存不足、元空间满jstat -gcutil, 检查Metaspace
Young GC频繁新生代过小、短命对象多调整-XX:NewSize, 检查代码
元空间增长类加载器泄漏、动态类生成jcmd VM.classloader_stats
线程数暴涨线程池配置问题、阻塞jstack, 线程dump分析
堆外内存高NIO DirectBuffer、JNIjcmd VM.native_memory

八、预防措施

# 1. 添加必要的JVM参数
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dumps
-XX:ErrorFile=/path/to/hs_err_pid%p.log
-Xlog:gc*,gc+age=debug:file=/path/to/gc.log

# 2. 设置合理的内存限制
-XX:MaxMetaspaceSize=512m
-XX:ReservedCodeCacheSize=256m
-Xss256k

# 3. 监控告警配置
# 关键指标:堆使用率 >80%,Full GC频率,元空间增长

总结 

到此这篇关于java线上问题排查之内存占用大解决步骤的文章就介绍到这了,更多相关java内存占用大内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Idea上传、拉取、更新项目到gitee的实现

    Idea上传、拉取、更新项目到gitee的实现

    该文章介绍了将Idea项目上传至Gitee的步骤,包括创建本地仓库、添加到缓冲区、提交到本地仓库、推送至远程仓库等以及从Gitee拉取项目的方法,整个过程涉及到创建远程仓库、项目上传、更新项目等和提交等内容
    2026-04-04
  • Spring Boot 一个注解搞定加密 + 解密 + 签名 + 验签(一文全解)

    Spring Boot 一个注解搞定加密 + 解密 + 签名

    本文介绍了一种基于Spring Boot 3.x的接口安全解决方案,通过自定义注解@ApiSecurity结合AOP切面,实现请求解密、验签、响应加密及加签的自动化处理,_springboot api aop 报文加解密
    2025-09-09
  • MyBatis中的XML实现和动态SQL实现示例详解

    MyBatis中的XML实现和动态SQL实现示例详解

    这篇文章主要介绍了MyBatis中的XML实现和动态SQL实现,我们可以将XML中重复出现的内容提取出来放到sql标签中,当需要用到sql标签中的内容时,用include标签将sql标签中的内容引进来即可,感兴趣的朋友跟随小编一起看看吧
    2024-02-02
  • JDK内置工具之常用工具和实战指令详解

    JDK内置工具之常用工具和实战指令详解

    jdk提供了很多强大的工具有命令行也有可视化的,这篇文章主要介绍了JDK内置工具之常用工具和实战指令的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-08-08
  • SpringBoot中配置文件敏感信息加密解密的实现方案详解

    SpringBoot中配置文件敏感信息加密解密的实现方案详解

    在现代企业级应用中,application.yml 或 application.properties 常用于配置数据库等中间件的连接信息,但将明文密码直接写入配置文件中存在诸多风险,下面我们就来看看如何对配置文件敏感信息加密解密吧
    2025-06-06
  • java使用GeoTools读取shp文件并画图的操作代码

    java使用GeoTools读取shp文件并画图的操作代码

    GeoTools是ArcGis地图与java对象的桥梁,今天通过本文给大家分享java使用GeoTools读取shp文件并画图,文章通过实例代码给大家介绍的非常详细,需要的朋友参考下吧
    2021-07-07
  • Springboot的yml配置文件用法

    Springboot的yml配置文件用法

    这篇文章主要介绍了Springboot的yml配置文件用法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • 客户端设置超时时间真的很重要

    客户端设置超时时间真的很重要

    今天小编就为大家分享一篇关于客户端设置超时时间真的很重要,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • Spring Cloud Gateway实现分布式限流和熔断降级的示例代码

    Spring Cloud Gateway实现分布式限流和熔断降级的示例代码

    这篇文章主要介绍了Spring Cloud Gateway实现分布式限流和熔断降级的示例代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-06-06
  • 浅谈HBase在SpringBoot项目里的应用(含HBaseUtil工具类)

    浅谈HBase在SpringBoot项目里的应用(含HBaseUtil工具类)

    这篇文章主要介绍了浅谈HBase在SpringBoot项目里的应用(含HBaseUtil工具类),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10

最新评论