验证 java 默认堆内存空间大小

java 进程的默认初始堆空间和物理内存有关,-Xms 指定的初始空间默认不小于物理内存的 1/64,-Xmx 指定的最大堆内存默认不小于物理内存的 1/4,接下来用工具来验证一下是不是这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 查看物理内存
free
总计 已用 空闲 共享 缓冲/缓存 可用
内存: 8144580 4216072 866168 10220 3062340 3618952
交换: 4193276 819200 3374076
# 用 python 计算物理内存的 1/4 和 1/64
>>> 8144580. / 1024 / 4
1988.4228515625

>>> 8144580. / 1024 / 64
124.27642822265625
# 查看 java 的默认配置(有删减)
java -XX:+PrintFlagsFinal -version | grep -i heapsize
size_t InitialHeapSize = 132120576 {product} {ergonomic}
size_t MaxHeapSize = 2086666240 {product} {ergonomic}
openjdk version "11.0.10" 2021-01-19
OpenJDK Runtime Environment (build 11.0.10+9-Ubuntu-0ubuntu1.18.04)
OpenJDK 64-Bit Server VM (build 11.0.10+9-Ubuntu-0ubuntu1.18.04, mixed mode, sharing)

# 用 python 转换单位,126.0 > 124.27, 1990.0 > 1988.42
>>> 132120576. / 1024**2
126.0
>>> 2086666240. / 1024**2
1990.0

# 再找一个内存不一样的机器验证一下,这台 windows 内存 16g
[D:\~]$ java -XX:+PrintFlagsFinal -version | findstr HeapSize
openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment AdoptOpenJDK-11.0.11+9 (build 11.0.11+9)
OpenJDK 64-Bit Server VM AdoptOpenJDK-11.0.11+9 (build 11.0.11+9, mixed mode)
size_t InitialHeapSize = 268435456 {product} {ergonomic}
size_t MaxHeapSize = 4294967296 {product} {ergonomic}

# python 转换单位,看以看出正好是物理内存的 1/64 和 1/4
>>> 268435456. / 1024**2
256.0
>>> 4294967296. / 1024**2
4096.0

验证完之后,还有个问题,如果配置的内存大于物理内存会怎样?会报错。

1
2
3
4
5
java -XX:+PrintFlagsFinal -Xms100g -Xmx100g -version
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x00007f1d06000000, 107374182400, 0) failed; error='Not enough space' (errno=12)
#
# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (mmap) failed to map 107374182400 bytes for committing reserved memory.

如果配置的内存小于物理内存,但大于可用内存会怎样?windows 报错,linux 正常运行,申请的内存空间以虚拟内存的形式反映到 top 上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java -Xms10g ch03/G1Testing
# linux 表现,可以开任意多个,只有虚拟内存 virt 显示比较大
进程 USER PR NI VIRT RES SHR 䞠%CPU %MEM TIME+ COMMAND
76248 ljc 20 0 12.893g 76.6m 24.0m S 0.0 0.6 0:00.66 java
76500 ljc 20 0 12.893g 76.1m 23.8m S 0.0 0.6 0:00.63 java
77080 ljc 20 0 12.893g 76.0m 23.8m S 0.0 0.6 0:00.20 java
# 看了下实际分配内存有 9.x MB
jstat -gc 76500
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
0.0 0.0 0.0 0.0 552960.0 4096.0 9932800.0 0.0 0.0 0.0 0.0 0.0 0 0.000 0 0.000 0.000

# windows 表现
OpenJDK 64-Bit Server VM warning: INFO: os::commit_memory(0x0000000580000000, 10737418240, 0) failed; error='页面文件太小,无法完成操作。' (DOS error/errno=1455)

# There is insufficient memory for the Java Runtime Environment to continue.

参考资料:
https://stackoverflow.com/questions/4667483/how-is-the-default-max-java-heap-size-determined
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gc-ergonomics.html