如何在Java8(SpringBoot)应用程序中设置最大非堆内存?

如何在Java8(SpringBoot)应用程序中设置最大非堆内存?,java,spring-boot,memory,Java,Spring Boot,Memory,我有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)。使用SpringBootAd

我有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)。使用SpringBootAdmin,我只能看到使用了~128MB。因此,我通过
java-Xmx512m…
将最大堆大小减少到512,现在,Spring Boot admin显示:

1.33 GB分配给非堆空间,但仅使用121 MB。为什么要为非堆空间分配这么多?我怎样才能减少

更新

根据top,每个Java进程大约占用2.4GB(VIRT):

更新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内部的本机缓冲区。没有通用开关或标志来同时限制所有不同的缓存和池


现在来回答房间里的大象。我认为你的真正的问题源于内存太少。您已经说过,您正在8GB机器上运行20个JVM实例,其堆空间限制为512MB。这是不可持续的。20 x 512MB=10GB堆,这超过了8GB总RAM的容量。而这还没有算在堆外/本机内存中。您需要提供更多的硬件资源,减少JVM计数,或者进一步减少堆/元空间和其他限制(我强烈建议不要这样做)。

首先-不,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内部的本机缓冲区。没有通用开关或标志来同时限制所有不同的缓存和池


现在来回答房间里的大象。我认为你的真正的问题源于内存太少。您已经说过,您正在8GB机器上运行20个JVM实例,其堆空间限制为512MB。这是不可持续的。20 x 512MB=10GB堆,这超过了8GB总RAM的容量。而这还没有算在堆外/本机内存中。您需要提供更多的硬件资源,减少JVM计数,或者进一步减少堆/元空间和其他限制(我强烈建议不要这样做)。

除了已经说过的内容之外,这是一篇关于JVM中的元空间的非常好的文章,默认情况下,它保留了大约1GB的空间(尽管实际上可能没有使用那么多)。因此,如果您有许多小型应用程序,并且希望减少使用/保留的内存量,那么您可以使用标志
-XX:MaxMetaspaceSize
来调整这一点。

除了已经说明的内容之外,这是一篇关于JVM中的元空间的非常好的文章,默认情况下,它保留了大约1GB的内存(尽管它实际上可能不会使用那么多)。因此,如果您有许多小型应用程序,并且希望减少已使用/保留的内存量,那么您可以使用标志
-XX:MaxMetaspaceSize
调整这是另一件事。

谢谢。这非常有帮助。不过,我仍然有一个疑问。根据top,我的每个Java进程的VIRT约为2.4GB。如果只有512 MB堆空间+127 MB非堆空间,我可以使用s已分配,那么为什么VIRT报告2.5GB?排名靠前的VIRT是虚拟内存,它包括所有代码、数据和共享库,加上已交换的页面和已映射但未使用的页面。因此,我敢打赌,这是很多东西的总和
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)