2017-04-04 5 views
5

Java 힙 할당이 2MB의 배수임을 알았습니다. 예를 들어 -Xmx values as 1021m, 1022m으로 JVM을 시작한 경우 힙 크기가 1022m 인 두 JVM이 모두 시작되었습니다. 마찬가지로 힙 크기 1023m,1024m1024m으로 시작됩니다.Java 힙 할당은 2MB의 배수입니다.

는 출력은 아래와 같다 : 두 경우

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) 

가 1,022메가바이트이다 1,071,644,672 바이트로 MaxHeapSize를 나타낸다.

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는 1,037,378,1824 바이트 (1024MB)입니다.

이 동작은 Xms와 비슷합니다.

질문 1 : 힙 크기가 지정된 값에서 2의 다음 배수로 변경되는 이유는 무엇입니까?

질문 2 : JVM이 실제로

질문 3 지정된 것과 다른 값으로 시작 왜 자바도 우리에게 경고하지 않습니다 플래그 또는 힙을 만들기 위해 JVM을 강제 할 수있는 방법이 있나요 1021mb?

질문 4 : 가설적인 상황에서 1023MB의 여유 메모리가 있습니다. 1023MB의 힙을 가진 JVM을 만들려고합니다. 위의 동작에 의해 실제로 사용할 수없는 1024MB로 시작하려고합니다. JVM 생성이 실패합니까?

+1

이것은 JVM보다는 운영 체제의 제한 사항이라고 생각합니다. 운영 체제는 일반적으로 "메모리 페이지"라는 개념 (처리에 할당 된 최소량의 실제 메모리)을 가지고 있습니다. 각 프로세스는 많은 페이지를 가질 수 있지만 하나의 페이지는 가질 수 없습니다. 귀하의 운영 체제는 페이지 크기가 2MB입니다. –

+0

@ M.Prokhorov 귀하의 의견은 거의 정확합니다, 유일한 수정은 * 가상 * 메모리의 최소 금액입니다. 더 간단한 메모리 페이지 - 가상, 메모리 프레임 - 물리적. – Eugene

+0

@Eugene 어떻게 윈도우 에서뿐만 아니라 리눅스에서 프로세스에 대한 가상 메모리의 최소 금액을 얻을 수 있습니까? –

답변

2

이것은 실제로 매우 흥미 롭습니다. 따라서과 같이 CPU 에서 지원되는 두 페이지 크기가 있습니다 (here).

4KB이 일반적입니다. 다른 두 개는 huge pages입니다.

페이지의 크기가 2MB 인 것을 볼 수 있습니다. 문제가 해결되었다고 말할 수 있습니다!

아시다시피 메모리는 실제로 예제와 2MB 덩어리로 정렬됩니다. 그리고 그것은 제가 여러분의 질문을 읽을 때 실제로 첫 반응이었습니다. 그런데 내 MAC을 시도하기로 결심했다. 이제 내가 가지고있는 CPU는 x86으로, 3KB의 모든 페이지 크기를 지원합니다 : 4KB, 2MB, 1GB.

Mac OS는 어떻습니까? 페이지 크기에 대해 실제로 읽혀지는 값의 소스 (jdk-9)는 hotspot/src/os/bsd/vm/os_bsd.cpp입니다. 그리고 실제 코드 :

Bsd::set_page_size(getpagesize()) 

나는 간단한 기능 getpagesize은 엑스 코드에서 그것을 실행하는 것이되었다. 놀람, 놀람! 그것은 단지 4KB이지만 힙은 여전히 ​​예제와 같이 정렬됩니다 (MB 기준).

그런 다음 여기에 page_size에 대한 정렬이 있음을 기억합니다. share/vm/memory/heap.cpp. 여기에 실제 방법이다 : 그것은 (내 경우 4KB) PAGE_SIZE로 나누어 있도록 메모리, 조금 성장하게됩니다

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); 
} 

; 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 정렬 힙을 만드는 유일한 있는지. 이 불확실성은이 파일 이 일부 매개 변수를 조정하기 위해 힙을 어떻게 자랄 수 있는지에 대한 의견이 전체적으로이라는 사실에서 기인합니다. 모든 세부 사항을 이해하는 것은 재미있을 것이다. 그러나 는 극단적으로 시간이 많이 걸리는를 소비한다. 그래서 나는 단념했다.

+0

와우, 훌륭한 발견. –

0

관찰 된 것은 JVM이 아닌 운영 체제에서 부과하는 제한 사항입니다. 프로세스에 메모리를 할당 할 때 운영 체제는 일반적으로 바이트를 작동시키지 않습니다. 그렇게하면 할당 및 특히 메모리에 대한 액세스가 매우 느려지므로 "메모리 페이지"라고하는 것을 사용합니다. here부터 시작하여 자세히 알아볼 수 있습니다.

운영 체제에 메모리 페이지 크기가 2MB 인 것 같습니다. 즉, 프로세스 요청이 자체 메모리를 할당 할 때 얻을 수있는 최소 메모리 양은 2MB입니다. 이는 사용자의 경우에 발생합니다.

질문의 두 번째 부분은 운영 체제의 메모리 페이지 크기를 변경하여 (실제로는이 옵션이있는) JVM이 2MB의 배수가 아닌 힙을 갖도록 할 수 있습니다. 그러나 OS 내에서 실행되는 모든 프로세스에 영향을 미치므로 예기치 않은 결과가 발생할 수 있습니다.

+0

불행히도 그렇지 않습니다. 페이지 크기가 4KB 인 Mac에서 실행했습니다. BSD에서 page_size가 어떻게 계산되는지에 대한 jdk-9 소스를 살펴 보았습니다 :'hotspot/src/os/bsd/vm/os_bsd.cpp'에'Bsd :: set_page_size (getpagesize()); 'getpagesize()'를 실행하면 4KB가 반환되므로 더 많은 정보가 있습니다 ... – Eugene

+0

@Eugene, 핫스팟 소스를 살펴보면'Universe.cpp'에'preferred_heap_base()'가 있습니다. 나는 많은 변수가 옮겨지고 (그리고 나는이 코드의 전문가와는 거리가 멀기 때문에) 정확하게 무엇을하는지에 대해별로 신경 쓰지는 않았다. 그러나 크기를 정렬하는 것처럼 보이기 때문에 우리가 다루는이 동작을 설명 할 수있다. 와. –

+0

여기에서 문제를 발견하고 답변을 제출해주세요. – Eugene