你在Mikhail Krestjaninoff的"
Analyzing java memory usage in a Docker container"中有一些线索:
(需要明确的是,三年后的2019年5月,the situation does improves with openJDK 8u212人)
Resident Set Size是进程当前分配和使用的物理内存量(无交换页).它包括代码、数据和共享库(在使用它们的每个进程中都会计算)
为什么docker统计信息与ps数据不同?
第一个问题的答案非常简单——Docker has a bug (or a feature - depends on your mood):它将文件缓存包含在总内存使用信息中.所以,我们可以避开这个指标,使用ps
条关于RSS的信息.
好吧,但是why is RSS higher than Xmx?
理论上,对于java应用程序
RSS = Heap size + MetaSpace + OffHeap size
其中OffHeap由线程堆栈、直接缓冲区、映射文件(库和JAR)和JVM代码itse组成
从JDK 1.8.40开始我们有101个!
如您所见,我已经向JVM添加了-XX:NativeMemoryTracking=summary
属性,所以我们可以从命令行调用它:
docker exec my-app jcmd 1 VM.native_memory summary
(这就是OP所做的)
不要担心"未知"部分——似乎NMT是一个不成熟的工具,无法处理CMS GC(当您使用另一个GC时,此部分将消失).
记住,that NMT displays “committed” memory, not "resident" (which you get through the ps command). In other words, a memory page can be committed without considering as a resident (until it directly accessed).
That means that NMT results for non-heap areas (heap is always preinitialized) might be bigger than RSS values
(这就是"Why does a JVM report more committed memory than the linux process resident set size?"的含义)
因此,尽管我们将jvm堆限制设置为256m,但我们的应用程序消耗了367M."其他"164M主要用于存储类元数据、编译代码、线程和GC数据.
前三个点通常是应用程序的常量,因此随着堆大小的增加,唯一增加的是GC数据
更一般地说,这之后似乎有issue 15020个报告了自docker 1.7以来的类似问题
我正在运行一个简单的Scala(JVM)应用程序,它将大量数据加载到内存中或从内存中取出
(docker stat
是reported as misleading before,因为它显然将文件缓存包含在总内存使用信息中)
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
It almost seems that the JVM is asking the OS for memory, which is allocated within the container, and the JVM is freeing memory as its GC runs, but the container doesn't release the memory back to the main OS. So... memory leak.