![](/img/trans.png)
[英]Difference with Linux VmRSS and the total commited memory of Java NativeMemoryTraking (NMT)
[英]Difference between Resident Set Size (RSS) and Java total committed memory (NMT) for a JVM running in Docker container
设想:
我有一个 JVM 在 docker 容器中运行。 我使用两个工具做了一些 memory 分析:1)顶部2) Java Native Memory 跟踪。 这些数字看起来令人困惑,我试图找出导致差异的原因。
问题:
Java 进程的 RSS 报告为 1272MB,总 Java Memory 报告为 79055 MB。 我如何解释 memory 1272 - 790.55 = 481.44 MB go 的 rest 在哪里?
为什么即使在查看了关于 SO 的这个问题之后,我仍想保持这个问题:
我确实看到了答案,并且解释很有意义。 However, after getting output from Java NMT and pmap -x, I am still not able to concretely map which java memory addresses are actually resident and physically mapped . 我需要一些具体的解释(带有详细的步骤)来找出导致 RSS 和 Java 总提交 memory 之间这种差异的原因。
顶部 Output
Java NMT
Docker memory 统计
图表
我有一个运行超过 48 小时的 docker 容器。 现在,当我看到包含以下内容的图表时:
那么,1.1 GB (RSS) 和 800 MB(Java 总提交内存)之间的 memory 是什么吃的?
您可以从Mikhail Krestjaninoff的 “ 分析Docker容器中的Java内存使用情况 ”中获得一些线索:
(并且要明确,在2019年5月,三年后, openJDK 8u212的情况确实有所改善 )
R esident S et S ize是进程当前分配和使用的物理内存量(没有换出的页面)。 它包括代码,数据和共享库(在使用它们的每个进程中计算)
为什么docker stats信息与ps数据不同?
第一个问题的答案非常简单 - Docker有一个bug(或一个功能 - 取决于你的心情) :它包括文件缓存到总内存使用信息。 因此,我们可以避免使用此指标并使用有关RSS的
ps
信息。好吧,好吧 - 但为什么RSS高于Xmx?
从理论上讲,在java应用程序的情况下
RSS = Heap size + MetaSpace + OffHeap size
其中OffHeap由线程堆栈,直接缓冲区,映射文件(库和jar)和JVM代码组成
从JDK 1.8.40开始,我们有Native Memory Tracker !
如您所见,我已经将
-XX:NativeMemoryTracking=summary
属性添加到JVM中,因此我们可以从命令行调用它:
docker exec my-app jcmd 1 VM.native_memory summary
(这是OP所做的)
不要担心“未知”部分 - 似乎NMT是一个不成熟的工具,无法处理CMS GC(当您使用另一个GC时,此部分会消失)。
请记住, NMT显示“已提交”内存,而不是“常驻”(通过ps命令获取)。 换句话说,可以提交存储器页面而不考虑作为驻留者(直到它被直接访问) 。
这意味着非堆区域(堆总是预初始化的)的NMT结果可能比RSS值大 。
(这就是“ 为什么JVM报告的内存比linux进程驻留集大小更多? ”)
因此,尽管我们将jvm堆限制设置为256m,但我们的应用程序消耗了367M。 “其他”164M主要用于存储类元数据,编译代码,线程和GC数据。
前三个点通常是应用程序的常量,因此随堆大小增加的唯一因素是GC数据。
这种依赖性是线性的,但“k
”系数(y = kx + b
)远小于1。
更一般地说,这似乎是问题15020 ,其报告了自docker 1.7以来的类似问题
我正在运行一个简单的Scala(JVM)应用程序,它将大量数据加载到内存中。
我将JVM设置为8G堆(-Xmx8G
)。 我有一台132G内存的机器,它不能处理超过7-8个容器,因为它们超过了我对JVM施加的8G限制。
( 之前报告的 docker stat
误导 ,因为它显然包含了总内存使用信息中的文件缓存)
docker stat
显示每个容器本身使用的内存比JVM应该使用的内存多得多。 例如:
CONTAINER CPU % MEM USAGE/LIMIT MEM % NET I/O
dave-1 3.55% 10.61 GB/135.3 GB 7.85% 7.132 MB/959.9 MB
perf-1 3.63% 16.51 GB/135.3 GB 12.21% 30.71 MB/5.115 GB
看起来JVM似乎要求操作系统在容器内分配内存,而JVM在GC运行时释放内存,但容器不会将内存释放回主操作系统。 所以...内存泄漏。
免责声明:我不是专家
我最近在重负载下发生了一起生产事件,Pod 的 RSS 大幅增加,Kubernetes 杀死了 Pod。 没有OOM错误异常,但是Linux以最硬核的方式停止了进程。
JVM 的 RSS 和总预留空间之间存在很大差距。 堆 memory,本机 memory,线程,一切看起来都不错,但是 RSS 很大。
发现这是由于malloc内部工作原理所致。 memory 中存在很大的差距,其中 malloc 从中获取了 memory 的块。 如果您的机器上有很多内核,malloc 会尝试适应并为每个内核分配自己的空间,以从中释放 memory 以避免资源争用。 设置export MALLOC_ARENA_MAX=2
解决了这个问题。 您可以在此处找到有关此情况的更多信息:
PS 我不知道为什么 RSS memory 有一个跳跃。 Pod 构建在 Spring Boot + Kafka 之上。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.