This is actually quite interesting. Thus, there are several page sizes that are supported by the processor at the same time , as described here .
4KB is ordinary; and the other two are called huge pages .
Looking at this, you see that one possible page size is 2MB , and you could say - the problem is solved!
Because you know that your memory is indeed aligned in 2MB chunks exactly from your examples. And that was my first reaction when I read your question. But then I decided to try my MAC. Now the processor has x86 , which apparently supports all 3 page sizes: 4 KB, 2 MB, 1 GB.
What about the Mac OS itself? I found the sources (jdk-9) of what value really reads for page size, i.e. in hotspot/src/os/bsd/vm/os_bsd.cpp . And the actual code:
Bsd::set_page_size(getpagesize())
I took this simple getpagesize function and ran it in Xcode. Surprise Surprise! this is only 4KB , but the heap is still aligned, as in your example ( MB in size).
Then I remembered that alignment is done here on share/vm/memory/heap.cpp : share/vm/memory/heap.cpp . Here is the actual method:
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); }
This will make the memory grow a bit, so it is divided by page_size ( 4KB in my case); what exactly did you say in the comment on divisibility on 4KB .
Now, to understand the following, I did a lot of searching ... jdk-9-sources|grep Xmx , and I got lucky! The lucky bits I found are here: share/vm/gc/shared/collectorPolicy.cpp and a wonderful comment:
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), eg 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; }
At this point, I'm not very sure that this is the only thing that makes the heap aligned on 2MB . This uncertainty comes from the fact that this file is filled with comments on how to increase the heap in order to configure some parameters. It would be interesting to understand all these details, but in a pinch it took a long time, so I gave up.