我注意到Java堆分配是2 MB的倍数。例如,我使用-Xmx values as 1021m, 1022m
启动了JVM,两个JVM都以1022m
的堆大小启动了。同样,堆大小1023m,1024m
以1024m
开头。
输出如下:
C:\Users\myuser>java -Xmx1021m -XX:+PrintFlagsFinal -version | findstr "MaxHeapSize"
uintx MaxHeapSize := 1071644672
{product}
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) Client VM (build 25.121-b13, mixed mode)
C:\Users\myuser>java -Xmx1022m -XX:+PrintFlagsFinal -version | findstr "MaxHeapSize"
uintx MaxHeapSize := 1071644672
{product}
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) Client VM (build 25.121-b13, mixed mode)
在这两种情况下,MaxHeapSize都显示为1071644672字节,即1022mb。
C:\Users\myuser>java -Xmx1023m -XX:+PrintFlagsFinal -version | findstr "MaxHeapSize"
uintx MaxHeapSize := 1073741824
{product}
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) Client VM (build 25.121-b13, mixed mode)
C:\Users\myuser>java -Xmx1024m -XX:+PrintFlagsFinal -version | findstr "MaxHeapSize"
uintx MaxHeapSize := 1073741824
{product}
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) Client VM (build 25.121-b13, mixed mode)
在这两种情况下,它都将MaxHeapSize显示为1073741824字节,即1024mb。
对于Xms,此行为类似。
问题1:为什么堆大小从指定的值更改为2的下一个倍数?
问题2:当JVM实际上以不同于指定值的值启动时,为什么Java甚至都没有警告我们
问题3:是否有某种标志或某种方式可以迫使JVM创建1021mb的堆?
问题4:在假设的情况下,说我的机器上有1023mb的可用内存,我尝试用1023mb的堆创建一个JVM。通过上述行为,它实际上尝试从不可用的1024mb开始。 JVM创建会失败吗?
最佳答案
这实际上很有趣。因此,如here所述,CPU 同时支持有几个页面大小。4KB
是通常的一种。其他两个称为huge pages
。
看着那,您会看到一种可能的页面大小是2MB
,并且您可以说-问题已解决!
如您所知,根据示例,您的内存确实按2MB的块对齐。这实际上是我阅读您的问题时的第一 react 。但是后来我决定尝试使用我的MAC。现在我拥有的CPU是x86
,它显然支持所有3个页面大小:4KB,2MB,1GB。
Mac OS本身呢?我找到了实际读取的页面大小值的来源(jdk-9),即hotspot/src/os/bsd/vm/os_bsd.cpp
。和实际的代码:
Bsd::set_page_size(getpagesize())
我使用了这个简单的函数
getpagesize
并在Xcode中运行它。惊喜,惊喜!它只是4KB
,但是堆仍然按照您的示例对齐(按MB
大小)。然后我记得在page_size上完成了对齐:
share/vm/memory/heap.cpp
。这是实际的方法: static size_t align_to_page_size(size_t size) {
const size_t alignment = (size_t)os::vm_page_size();
assert(is_power_of_2(alignment), "no kidding ???");
return (size + alignment - 1) & ~(alignment - 1);
}
那将使内存稍微增加一点,以便可以被page_size(在我的情况下为
4KB
)整除。这正是您在评论中所说的被4KB
整除的意思。现在了解下一个,我做了很多搜索...
jdk-9-sources|grep Xmx
,我很幸运!我发现的幸运位在这里:share/vm/gc/shared/collectorPolicy.cpp
和一个很棒的评论: size_t CollectorPolicy::compute_heap_alignment() {
// The card marking array and the offset arrays for old generations are
// committed in os pages as well. Make sure they are entirely full (to
// avoid partial page problems), e.g. if 512 bytes heap corresponds to 1
// byte entry and the os page size is 4096, the maximum heap size should
// be 512*4096 = 2MB aligned.
size_t alignment = CardTableRS::ct_max_alignment_constraint();
if (UseLargePages) {
// In presence of large pages we have to make sure that our
// alignment is large page aware.
alignment = lcm(os::large_page_size(), alignment);
}
return alignment;
}
在这一点上,我不确定这是使堆与
2MB
对齐的唯一方法。这种不确定性来自以下事实:该文件是关于如何增长堆以调整某些参数的注释的完整。了解所有这些细节会很有趣,但是非常耗时,所以我放弃了。