Java heap distribution is 2 MB

I noticed that the Java heap distribution is a multiple of 2 MB. For example, I started the JVM with -Xmx values as 1021m, 1022m , and both JVMs started with a heap size of 1022m . Similarly, heap sizes of 1023m,1024m started at 1024m .

The output is below:

 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) 

In both cases, it shows MaxHeapSize as 1071644672 bytes, which is 1022 MB.

 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) 

In both cases, it shows MaxHeapSize as 1073741824 bytes, which is 1024 MB.

This behavior is similar to Xms.

Question 1: Why do heap sizes change from given values ​​to the next multiple of 2?

Question 2: Why Java does not even warn us when the JVM really started with a value other than the specified

Question 3: Is there a flag or some way to get the JVM to create a bunch of 1021mb?

Question 4: In a hypothetical situation, they say that I have 1023 MB of free memory on my machine, and I'm trying to create a JVM with a bunch of 1023 MB. By the action described above, he is actually trying to start with 1024mb, which is not available. Will the creation of the JVM work?

+5
source share
2 answers

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.

+2
source

What you are observing is a restriction imposed by your operating system, not the JVM. When allocating memory for a process, operating systems usually do not control bytes (because it will make the allocation and especially memory access a very slow process) - they use the so-called "memory page". You can learn more about this from here .

Thus, your operating system has a memory page size of 2 MB, which means that when process requests allocate some memory for themselves, then at least it can be equal to 2 MB, which happens in your case.

In the second part of your question, you can really force the JVM to have a bunch that is not a multiple of 2 MB by changing the size of the memory page of your operating system (some of them have this option). However, this can have unforeseen consequences, as it will affect all processes running inside this OS.

0
source

Source: https://habr.com/ru/post/1266309/


All Articles