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.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运行时释放内存,但容器不会将内存释放回主操作系统.所以...内存泄漏.
归档时间: |
|
查看次数: |
11759 次 |
最近记录: |