驻留集大小(RSS)与在Docker容器中运行的JVM的Java总提交内存(NMT)之间的差异

sun*_*985 34 java linux memory jvm docker

场景:

我有一个在docker容器中运行的JVM.我使用两个工具进行了一些内存分析:1)top 2)Java Native Memory Tracking.这些数字看起来很混乱,我试图找出导致差异的原因.

题:

对于Java进程,RSS报告为1272MB,报告的总Java内存为790.55 MB.我怎么能解释内存的其余部分1272 - 790.55 = 481.44 MB去哪了?

为什么我想在SO上查看这个问题后仍然保持这个问题的开放性:

我确实看到了答案,解释也很有道理.但是,从Java NMT和pmap -x获取输出后,我仍然无法具体映射实际驻留和物理映射的Java内存地址.我需要一些具体的解释(详细步骤)来找出导致RSS和Java Total提交内存之间差异的原因.

最高输出

在此输入图像描述

Java NMT

在此输入图像描述

Docker内存统计信息

在此输入图像描述

图表

我有一个运行48小时以上的码头集装箱.现在,当我看到一个图表包含:

  1. 给予docker容器的总内存= 2 GB
  2. Java Max Heap = 1 GB
  3. 承诺总量(JVM)=始终小于800 MB
  4. 堆使用(JVM)=始终小于200 MB
  5. 非堆使用(JVM)=始终小于100 MB.
  6. RSS =大约1.1 GB.

那么,在1.1 GB(RSS)和800 MB(Java Total committed memory)之间占用的内存是什么?

在此输入图像描述

Von*_*onC 35

您可以从Mikhail Krestjaninoff的 " 分析Docker容器中的Java内存使用情况 "中获得一些线索:

R esident S et S ize是进程当前分配和使用的物理内存量(没有换出的页面).它包括代码,数据和共享库(在使用它们的每个进程中计算)

为什么docker stats信息与ps数据不同?

第一个问题的答案非常简单 - Docker有一个bug(或一个功能 - 取决于你的心情):它包括文件缓存到总内存使用信息.因此,我们可以避免使用此指标并使用ps有关RSS的信息.

好吧,好吧 - 但为什么RSS高于Xmx?

从理论上讲,在java应用程序的情况下

RSS = Heap size + MetaSpace + OffHeap size
Run Code Online (Sandbox Code Playgroud)

其中OffHeap由线程堆栈,直接缓冲区,映射文件(库和jar)和JVM代码组成

JDK 1.8.40开始,我们有Native Memory Tracker!

如您所见,我已经-XX:NativeMemoryTracking=summary向JVM 添加了属性,因此我们可以从命令行调用它:

docker exec my-app jcmd 1 VM.native_memory summary
Run Code Online (Sandbox Code Playgroud)

(这是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 heap(-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
Run Code Online (Sandbox Code Playgroud)

看起来JVM似乎要求操作系统在容器内分配内存,而JVM在GC运行时释放内存,但容器不会将内存释放回主操作系统.所以...内存泄漏.

  • @sunsin1985 “什么占用了 1.1 GB (RSS) 和 800 MB(Java 总提交内存)之间的内存?” 我怀疑这些是文章中提到的“存储类元数据、编译代码、线程和 GC 数据”,而且如果容器一直不释放它,GC 可能不会释放任何东西。 (2认同)
  • 我认为这里的答案不是所问问题的答案。问题是为什么java进程RSS > JVM heap+non_heap。答案是相反的问题:为什么 JVM heap+non_heap 可能 > java 进程 RSS。@VonC 我错过了什么吗? (2认同)

归档时间:

查看次数:

11759 次

最近记录:

6 年,3 月 前