当前位置: 首页 > news >正文

k8s-pod部署java应用,jvm内存正常,但是pod内存不足oom排查

目录

  • 目的
  • 步骤
    • 进入k8s-pod终端
    • 通过 top 查看 pod 内存使用情况
    • 通过 ps 查看 jvm 参数
    • 通过 jstat 查看堆内存
    • 查询直接内存使用情况
    • 查询线程内存使用情况
      • 统计真实线程数
    • 定位线程泄漏的来源
      • 按线程状态分类
      • 按线程名称前缀分类
      • 查看具体线程堆
    • 验证线程泄露原因
      • 通过代码检查验证

目的

k8s-pod部署java应用,jvm内存正常,但是pod内存不足oom排查

步骤

进入k8s-pod终端

通过 kubectl 进入 pod 或者直接操作 pod 命令。

通过 top 查看 pod 内存使用情况

可以直接在 pod 中执行 top 命令,或者通过 kubectl top pod <你的pod名称> 的方式执行。

top - 17:08:40 up 43 days, 23:39,  0 users,  load average: 1.21, 1.16, 1.17
Tasks:   7 total,   1 running,   6 sleeping,   0 stopped,   0 zombie
%Cpu(s):  6.9 us,  0.5 sy,  0.0 ni, 91.9 id,  0.0 wa,  0.6 hi,  0.1 si,  0.0 st
MiB Mem :  63003.8 total,  12938.7 free,  19556.6 used,  30508.4 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.  42743.2 avail Mem PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                                                                                                                                                                                                                                            7 admin     20   0   30.7g   7.6g  29580 S   9.3  12.4 364:25.59 java                                                                                                                                                                                                                                               
1223533 admin     20   0   21280   4540   3844 R   0.3   0.0   0:00.02 top                                                                                                                                                                                                                                                1 admin     20   0   16696   3400   3140 S   0.0   0.0   0:00.00 sh                                                                                                                                                                                                                                                 
1213439 admin     20   0   16696   3332   3072 S   0.0   0.0   0:00.00 sh                                                                                                                                                                                                                                                 
1213445 admin     20   0   16696    276      0 S   0.0   0.0   0:00.00 sh                                                                                                                                                                                                                                                 
1213446 admin     20   0   15900   2408   2252 S   0.0   0.0   0:00.00 script                                                                                                                                                                                                                                             
1213448 admin     20   0   16936   3888   3440 S   0.0   0.0   0:00.00 bash 

可以看到 java 进程总共使用内存 7.6g,而 java 进程的总内存占用 = 堆内存(-Xmx控制) + 非堆内存(元空间、直接内存、线程栈、JVM 自身开销等)。
接下来排查非堆内存和 jvm 堆内存各自占用多少。

通过 ps 查看 jvm 参数

ps -ef | grep java
admin          7       1  5 1004 ?      06:04:35 java -server -Xms4g -Xmx7g -Xmn2356m -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -Dfile.encoding=utf-8 -Djasypt.encryptor.password=xxxx -Djava.security.egd=file:/dev/./urandom -jar /home/admin/application/xxxx/bootstrap.jar --server.port=8080 --spring.profiles.active=xxxx

通过 jstat 查看堆内存

jstat -gc 7 1000 3S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
241216.0 241216.0  0.0   31466.1 1930112.0 349175.8 2201600.0  1772567.1  226328.0 213438.7 26928.0 24826.2    613    7.113  32      2.237    9.350
241216.0 241216.0  0.0   31466.1 1930112.0 354020.2 2201600.0  1772567.1  226328.0 213438.7 26928.0 24826.2    613    7.113  32      2.237    9.350
241216.0 241216.0  0.0   31466.1 1930112.0 354180.6 2201600.0  1772567.1  226328.0 213438.7 26928.0 24826.2    613    7.113  32      2.237    9.350

从jstat -gc的输出结果来看,当前堆内存的实际使用量远低于-Xmx7g的上限。
Java 进程总物理内存约 7.6g,减去堆实际使用的 2.01g,非堆内存占用约 5.59g。
非堆内存主要包括:元空间(Metaspace)、直接内存(Direct Memory)、线程栈、JVM 自身开销等。其中

  • 元空间(MU):213438.7 KB ≈ 0.203g(正常,未超限)
  • 压缩类空间(CCSU):24826.2 KB ≈ 0.023g(正常)
    因此,超限的非堆内存大概率来自直接内存或线程栈,接下来需要重点排查。

查询直接内存使用情况

直接内存用于 NIO 操作(如 Netty、文件 IO),默认无上限(与堆上限一致,即 7g),是最可能超限的部分。

[application]$ cat /proc/7/cmdline | tr '\0' ' ' | grep MaxDirectMemorySize // 确认是否有直接内存限制
[application]$ jcmd 7 VM.native_memory summary | grep "Direct" // 查看直接内存实际使用,若支持,直接显示直接内存使用
Picked up JAVA_TOOL_OPTIONS:  -javaagent:/home/admin/.opt/AliyunJavaAgent/aliyun-java-agent.jar...
[application]$ grep -E "anon_inode|java.nio" /proc/7/maps | awk '{print $2}' | grep -v '-' | awk '{sum += $1} END {print sum/1024/1024 " MB"}' // 若jcmd不支持,用内存映射文件间接判断
0 MB

通过grep -E “anon_inode|java.nio” /proc/7/maps计算直接内存约为 0MB,结合jcmd无结果,说明直接内存不是非堆超限的原因。

查询线程内存使用情况

排除直接内存和线程栈后,剩余的非堆内存(约 5.59g)可能来自:

  • JVM Code Cache(存储即时编译的代码,默认上限约 240MB,但可能因配置异常增大)
  • GC 相关内存(如标记 - 清除算法的内存开销、GC 日志缓冲区等)
  • 第三方 Agent 内存(你的启动参数包含 AliyunJavaAgent、MSE 等 Agent,可能存在内存泄漏或过度占用)
  • 本地内存泄漏(如 JNI 调用分配的 C 堆内存未释放,JVM 无法跟踪)

统计真实线程数

[application]$ jstack 7 | grep -c "tid=" // 统计所有包含"tid="的线程(jstack中线程的标准标识)
Picked up JAVA_TOOL_OPTIONS:  -javaagent:/home/admin/.opt/AliyunJavaAgent/aliyun-java-agent.jar...
12825
[application]$ ps -T -p 7 | wc -l // 直接查看进程的线程总数(操作系统层面)
12862

数量完全超出正常 Java 应用的线程范围(正常 Web 应用通常几百到几千个线程)。
jvm 未显式设置-Xss(线程栈大小),默认值通常为 1MB / 线程(不同 JDK 版本略有差异)。
总线程栈内存占用 ≈ 12861 线程 × 1MB / 线程 ≈ 12.56GB,这已经远超 pod 的 8GB 内存限制!
之前计算的 “非堆内存约 5.59g”,本质就是线程栈的大量占用(因部分线程可能未完全初始化或栈未占满,所以实际占用低于 12.56GB,但依然远超安全阈值)。
下一步需要定位线程泄漏的来源。

定位线程泄漏的来源

按线程状态分类

jstack 7 | grep -E "java.lang.Thread.State: (RUNNABLE|WAITING|TIMED_WAITING|BLOCKED)" | awk '{print $NF}' | sort | uniq -c | sort -nr11328 RUNNABLE749 (parking)714 (sleeping)16 monitor)

按线程名称前缀分类

jstack 7 | grep -E '"[^"]+" #' | awk -F'"' '{print $2}' | awk '{print substr($0,1,20)}' | sort | uniq -c | sort -nr | head -n 1011152 httpclient-dispatch-697 idle-connection-evic200 DubboServerHandler-1122 com.alibaba.nacos.cl70 aliyun-log-producer-62 172024109152_944709_49 nacos-grpc-client-ex48 NettyClientPublicExe40 ConsumeMessageThread16 NettyServerWorker-8-

查看具体线程堆

jstack 7 | awk -v RS='' '/httpclient-dispatch-/' | head -n 2"httpclient-dispatch-16" #1227473 daemon prio=5 os_prio=0 tid=0x00007f25282cc800 nid=0x12bafc runnable [0x00007f20af736000]java.lang.Thread.State: RUNNABLEat sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)- locked <0x00000006851e91a0> (a sun.nio.ch.Util$3)- locked <0x00000006851e9190> (a java.util.Collections$UnmodifiableSet)- locked <0x00000006851e91b0> (a sun.nio.ch.EPollSelectorImpl)at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)at com.aliyun.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:113)at com.aliyun.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:86)at com.aliyun.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44)at java.lang.Thread.run(Thread.java:748)
"httpclient-dispatch-15" #1227472 daemon prio=5 os_prio=0 tid=0x00007f25282cb000 nid=0x12bafb runnable [0x00007f20af534000]java.lang.Thread.State: RUNNABLEat sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)- locked <0x000000068549d170> (a sun.nio.ch.Util$3)- locked <0x000000068549d160> (a java.util.Collections$UnmodifiableSet)- locked <0x000000068549d180> (a sun.nio.ch.EPollSelectorImpl)at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)at com.aliyun.apache.hc.core5.reactor.SingleCoreIOReactor.doExecute(SingleCoreIOReactor.java:113)at com.aliyun.apache.hc.core5.reactor.AbstractSingleCoreIOReactor.execute(AbstractSingleCoreIOReactor.java:86)at com.aliyun.apache.hc.core5.reactor.IOReactorWorker.run(IOReactorWorker.java:44)at java.lang.Thread.run(Thread.java:748)

从线程信息推测应用使用的阿里云 Apache HttpClient(aliyun.apache.hc.core5)存在严重线程泄漏。下一步需要验证推测是否正确

验证线程泄露原因

通过代码检查验证

检查代码是否存在新建 HttpClient 实例,且未正确关闭的场景。

http://www.dtcms.com/a/462892.html

相关文章:

  • 公司网站建设合同需要交印花税中山专业网站建设模板代理
  • 网站开发需要解决难题项目网络图经常被称为
  • OSPF的高级特性
  • 安徽省建设工程造价管理网站wordpress嵌入php代码
  • 专门做网站的app怎样做网络推广优选豪升网络好
  • 网站空间150m跨境电商平台有哪些?列举5个
  • 怎么做网盘网站高培淇自己做的网站
  • spring ai mcp + 编写自动测试mcp服务端功能
  • 设备管理平台项目部署实验流程
  • 织梦网站文章发布信息模板下载去掉wordpress 上一篇
  • 有铁芯直线电机扰动力建模方法介绍
  • 图解 bulkProcessor(调度器 + bulkAsync() + Semaphore)
  • 监控系统3 - LVGL
  • 20-数组
  • 防水补漏东莞网站建设河北省建设厅办事大厅网站
  • logosc网站怎么做的减少wordpress响应时间
  • ps做的网站在线设计装修的网站
  • Python-UV环境管理实战
  • 江门建设建筑网站一个人做网站难吗
  • 网站开发使用哪些开发语言长沙的网站建设
  • 光效网站制作网站副本
  • 网站推广经典案例网站优化关键词排名自己怎么做
  • 电子商务网站建设实验原理集约化网站群建设
  • RocketMQ如何使用Netty
  • 哪个网站可以做片头深圳小程序建设公司
  • 腾讯开始数字人mousetalk 部署笔记
  • 做影视网站侵权吗免费刷推广链接的网站
  • 悠悠我心的个人网站怎么做网站侧边栏怎么做
  • 基于机器学习方法的网球比赛胜负趋势预测
  • 金华职院优质校建设网站网站设置在设备之间共享什么意思