[英]How to set max non-heap memory in a Java 8 (Spring Boot) application?
我有 20 个 Spring Boot (2.3) 嵌入式 Tomcat 应用程序在 8GB 的 Linux 机器上运行。 所有应用程序都是 Java 1.8 应用程序。 机器内存不足,结果 Linux 开始杀死我的一些应用程序进程。
使用 Linux top 和 Spring Boot admin,我注意到最大内存堆设置为 2GB:
java -XX:+PrintFlagsFinal -version | grep HeapSize
结果,这 20 个应用程序中的每一个都试图获得 2GB 的堆大小(物理内存的 1/4)。 使用 Spring Boot admin 我只能看到大约 128 MB 正在使用。 所以我通过java -Xmx512m ...
将最大堆大小减少到 512 java -Xmx512m ...
现在,Spring Boot 管理员显示:
1.33 GB 分配给非堆空间,但仅使用了 121 MB。 为什么这么多被分配给非堆空间? 我怎样才能减少?
更新
根据 top,每个 Java 进程占用大约 2.4GB (VIRT):
KiB Mem : 8177060 total, 347920 free, 7127736 used, 701404 buff/cache
KiB Swap: 1128444 total, 1119032 free, 9412 used. 848848 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2547 admin 20 0 2.418g 0.372g 0.012g S 0.0 4.8 27:14.43 java
.
.
.
更新 2
我为其中一个进程运行jcmd 7505 VM.native_memory
并报告:
7505:
Native Memory Tracking:
Total: reserved=1438547KB, committed=296227KB
- Java Heap (reserved=524288KB, committed=123808KB)
(mmap: reserved=524288KB, committed=123808KB)
- Class (reserved=596663KB, committed=83423KB)
(classes #15363)
(malloc=2743KB #21177)
(mmap: reserved=593920KB, committed=80680KB)
- Thread (reserved=33210KB, committed=33210KB)
(thread #32)
(stack: reserved=31868KB, committed=31868KB)
(malloc=102KB #157)
(arena=1240KB #62)
- Code (reserved=254424KB, committed=27120KB)
(malloc=4824KB #8265)
(mmap: reserved=249600KB, committed=22296KB)
- GC (reserved=1742KB, committed=446KB)
(malloc=30KB #305)
(mmap: reserved=1712KB, committed=416KB)
- Compiler (reserved=1315KB, committed=1315KB)
(malloc=60KB #277)
(arena=1255KB #9)
- Internal (reserved=2695KB, committed=2695KB)
(malloc=2663KB #19903)
(mmap: reserved=32KB, committed=32KB)
- Symbol (reserved=20245KB, committed=20245KB)
(malloc=16817KB #167011)
(arena=3428KB #1)
- Native Memory Tracking (reserved=3407KB, committed=3407KB)
(malloc=9KB #110)
(tracking overhead=3398KB)
- Arena Chunk (reserved=558KB, committed=558KB)
(malloc=558KB)
首先 - 不,没有分配1.33GB 。 在屏幕截图上,您分配了 127MB 的非堆内存。 1.33GB 是最大限制。
我看到您的元空间大约为 80MB,这应该不会造成问题。 剩下的内存可以由很多东西组成。 压缩类、代码缓存、本机缓冲区等...
要详细了解什么占用了堆外内存,您可以查询 MBean java.lang:type=MemoryPool,name=*
,例如通过带有 MBean 插件的 VisualVM。
但是,您的应用程序可能只是占用了过多的本机内存。 例如,来自 Netty 的许多 I/O 缓冲区可能是罪魁祸首(被java.nio.DirectByteBuffer
)。 如果这是罪魁祸首,您可以例如使用标志-Djdk.nio.maxCachedBufferSize
限制DirectByteBuffer
的缓存,或使用-XX:MaxDirectMemorySize
设置限制。 要确定究竟是什么在占用您的 RAM,您必须创建一个堆转储并对其进行分析。
因此,要回答您的问题“为什么将这么多空间分配给非堆空间?我该如何减少?” 没有很多分配给非堆空间。 其中大部分是用于 I/O 和 JVM 内部的本机缓冲区。 没有通用开关或标志来一次性限制所有不同的缓存和池。
现在要对房间里的大象讲话。 我认为您真正的问题源于 RAM 很少。 你说过你在 8GB 机器上运行 20 个 JVM 实例,限制为 512MB 的堆空间。 那是不可持续的。 20 x 512MB = 10GB 的堆,这超出了 8GB 总 RAM 的容量。 那是在您甚至计算堆外/本机内存之前。 您需要提供更多硬件资源、减少 JVM 数量或进一步减少堆/元空间和其他限制(我强烈建议不要这样做)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.