默认情况下,Java 8 在容器内运行时是否总是消耗至少 1GB 的 RAM?

Ale*_*hin 2 java jvm docker kubernetes

我们正在 Kubernetes 集群中运行 Java 应用程序。应用程序本身对 RAM 的需求并不高,但我注意到它总是消耗 1GB。

kubectl top pods
NAME                                                              CPU(cores)   MEMORY(bytes)
my-application-c0ffee                                             100m           1127Mi
my-application-c0ffee                                             100m           1109Mi
Run Code Online (Sandbox Code Playgroud)

当我检查jcmd <pid> GC.heap_info容器内部时,我得到以下信息:

def new generation   total 89216K, used 12090K [0x00000000bc200000, 0x00000000c22c0000, 0x00000000d2c00000)
  ...
tenured generation   total 197620K, used 151615K [0x00000000d2c00000, 0x00000000decfd000, 0x0000000100000000)
  ...
Metaspace       used 146466K, capacity 152184K, committed 152576K, reserved 1183744K
  class space    used 18171K, capacity 19099K, committed 19200K, reserved 1048576K
Run Code Online (Sandbox Code Playgroud)

据我了解,默认情况下,Java 保留 1GB 的虚拟内存大小用于存储类信息(为了使用 32 位引用以压缩方式引用它,应事先保留此内存块)。在容器外运行时没什么大不了的,因为实际上并未提交此内存。它只是一个保留的地址空间。

但是,如果在容器内运行,保留内存变为已提交,则情况似乎完全不同。

这是否意味着在容器中运行的 Java 将默认消耗至少 1GB 的 RAM?除了明确设置之外,还有其他方法可以解决-XX:CompressedClassSpaceSize吗?

apa*_*gin 5

在容器内部运行的情况下,保留的内存被提交

不,保留的内存不会“提交”。虚拟大小和驻留集大小是不同的度量标准,无论是否在容器中。位于物理内存中的是RSS。

kubectl top 不会向您显示 RSS,而是所谓的“工作集”,它并不总是与实际内存使用情况相匹配。

这是否意味着在容器中运行的 Java 将默认消耗至少 1GB 的 RAM?

不。

有没有其他方法可以解决这个问题

这取决于你的目标。如果您想查看实际的容器内存统计信息,请查看/sys/fs/cgroup/memory/.../memory.statsmemory.usage_in_bytes。或者,如果您使用 docker,请运行docker stats.

如果您想减少进程的虚拟内存,请关闭-XX:-UseCompressedClassPointers.