9

我有一个在 Docker 容器内的 Java 8 上运行的 Java 应用程序。该过程启动了一个 Jetty 9 服务器,并且正在部署一个 Web 应用程序。传递了以下 JVM 选项:-Xms768m -Xmx768m.

最近我注意到该进程消耗大量内存:

$ ps aux 1
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
app          1  0.1 48.9 5268992 2989492 ?     Ssl  Sep23   4:47 java -server ...

$ pmap -x 1
Address           Kbytes     RSS   Dirty Mode  Mapping
...
total kB         5280504 2994384 2980776

$ jcmd 1 VM.native_memory summary
1:

Native Memory Tracking:

Total: reserved=1378791KB, committed=1049931KB
-                 Java Heap (reserved=786432KB, committed=786432KB)
                            (mmap: reserved=786432KB, committed=786432KB) 

-                     Class (reserved=220113KB, committed=101073KB)
                            (classes #17246)
                            (malloc=7121KB #25927) 
                            (mmap: reserved=212992KB, committed=93952KB) 

-                    Thread (reserved=47684KB, committed=47684KB)
                            (thread #47)
                            (stack: reserved=47288KB, committed=47288KB)
                            (malloc=150KB #236) 
                            (arena=246KB #92)

-                      Code (reserved=257980KB, committed=48160KB)
                            (malloc=8380KB #11150) 
                            (mmap: reserved=249600KB, committed=39780KB) 

-                        GC (reserved=34513KB, committed=34513KB)
                            (malloc=5777KB #280) 
                            (mmap: reserved=28736KB, committed=28736KB) 

-                  Compiler (reserved=276KB, committed=276KB)
                            (malloc=146KB #398) 
                            (arena=131KB #3)

-                  Internal (reserved=8247KB, committed=8247KB)
                            (malloc=8215KB #20172) 
                            (mmap: reserved=32KB, committed=32KB) 

-                    Symbol (reserved=19338KB, committed=19338KB)
                            (malloc=16805KB #184025) 
                            (arena=2533KB #1)

-    Native Memory Tracking (reserved=4019KB, committed=4019KB)
                            (malloc=186KB #2933) 
                            (tracking overhead=3833KB)

-               Arena Chunk (reserved=187KB, committed=187KB)
                            (malloc=187KB) 

如您所见,RSS (2,8GB) 与 VM 本机内存统计实际显示的内容(提交 1.0GB,保留 1.3GB)之间存在巨大差异。

为什么会有如此巨大的差异?我知道 RSS 还显示了共享库的内存分配,但在分析pmap详细输出后,我意识到这不是共享库的问题,而是被称为 [anon] 结构的某些东西消耗了内存。为什么JVM分配了这么多匿名内存块?

我正在搜索并发现以下主题: 为什么 JVM 报告的已提交内存比 linux 进程驻留集大小更多? 但是,这里描述的情况有所不同,因为 RSS 显示的内存使用量少于 JVM 统计信息。我有相反的情况,无法弄清楚原因。

4

3 回答 3

4

我在我们的一个 Apache Spark 作业中遇到了类似的问题,我们将我们的应用程序作为一个胖 jar 提交,在分析线程转储后,我们认为 Hibernate 是罪魁祸首,我们曾经在实际使用的应用程序启动时加载休眠类java.util.zip.Inflater.inflateBytes要读取休眠类文件,这超出了我们的本地常驻内存使用量几乎 1.5 gb,这是休眠中针对此问题提出的一个错误 https://hibernate.atlassian.net/browse/HHH-10938?attachmentOrder=desc,评论中建议的补丁对我们有用,希望这会有所帮助。

于 2016-12-10T04:53:32.527 回答
2

根据以下文章深入分析后:https ://gdstechnology.blog.gov.uk/2015/12/11/using-jemalloc-to-get-to-the-bottom-of-a-memory-leak/ 我们发现问题与 java.util.zip.Inflater 的内存分配有关。

仍然需要找出调用 java.util.zip.Inflater.inflateBytes 并寻找可能的解决方案。

于 2016-09-29T17:33:55.553 回答
1

NMT 仅跟踪 JVM 管理的部分内存,它不跟踪本机 3rd 方库或内存映射/直接字节缓冲区使用的内存。

于 2016-09-25T09:32:53.457 回答