JVM 堆外内存溢出问题

在项目中遇到配置了 JVM 堆大小之后还是发现真实使用的内存比配置的内存大了很多,接下来就是一列的排查最终解决。

  1. 排查这个问题需要明白 JVM 的内存使用
  • 我们平时只是控制 JVM 堆大小,但是还有一块应用运行临时区可以直接在服务器开辟内存空间

  • 所以真实的使用内存大小需要 JVM 空间加上应用运行临时区

  • 临时区包含:字节缓冲区、序列化、自定义类型而且经了解没办法GC,高手要请教C++自己优化内存空间。

  • 搞清楚 JVM 里面的运行机制下一步就要看一下如何定位问题,究竟是哪里的代码出了问题

  1. 定位问题

  • 首先我怀疑是有流没有关掉
    • 打印GC日志 -Xlog:gc*:file=/opt/app/dumps/gc.log

    • 观察系统中 GC 后内存变化

    • 或者使用jstat -gcutil pid 或者 arthas 等工具查看GC的回收变化

    • 看完之后GC正常没有清除不掉的空间

  • 使用命令定位
# 查看历史
jmap -histo <PID>
​
## 查看垃圾回收情况
jstat -gcutil <PID>
​
## 打印内存使用情况
jcmd <PID> VM.native_memory summary scale=MB

jmap 是 Java Memory Map 工具的一部分,用于分析和管理 Java 虚拟机(JVM)的内存。jmap -histo 命令用于显示 Java 堆内存中的对象实例的直方图。

命令的输出通常包括以下列:

  • Num: 对象的序号。

  • # Instances: 对象实例的数量。

  • # Bytes: 所有实例占用的总字节数。

  • Class Name: 对象的类名。

例子

yaml复制代码 num     #instances         #bytes  class name
----------------------------------------------
   1:          1000          51200  [B
   2:           500          30000  java.lang.String
   3:           200          16000  java.util.ArrayList
   ...

这个输出表示 java.lang.String 类有 500 个实例,占用 30000 字节的内存。

查看内存占用情况没有发现自定义类型

  • 导出当前的内存地址
# 内存地址详情
pmap -x <PID> | sort -n -k3 > pmap-sorted.txt

可以看到所有内存中存储的空间,这块要想看具体内存空间中有哪些内容需要自己去找一下;

  • 打印堆文件查看对文件的垃圾对象有哪些顽固分子
​
## 堆转储存
jmap -dump:format=b,file=./dumpfile.hprof 1
​

最终发现都是一些字节和基础类型。

  • 打印当前线程栈信息
# top命令查看当前资源占用情况
top
# 紧接着大写的H 可以查看当前所有线程的运行情况
-H
## 可以打印线程栈信息到文件,也可以使用arthas工具
jstack -l 1 > stack.txt
​

总结:打印出当前所有线程信息发现占用CPU高的线程栈里面的方法,可以定位一般性问题

一顿操作猛如虎,但是我们堆外内存如何控制还是没有找到源头,最终逛论坛很遗憾的发现运行时区域的内存是无法限制的。只能取一个合理值在k8s pod 中给他限制。所以需要把业务节点和计算节点分开部署,保证业务的稳定,计算节点要给一个上线崩溃自启。

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值