자바 단일 개체 메모리 레이아웃 .md

우리는 자바 (방법 문서의 공유 메모리 크기의 자바 객체를 얻을 수있는 공유 메모리 크기를 얻기 객체 유틸리티 클래스를 작성 ObjectSizeFetcher후, 우리는 자바 객체의 다양한 종류에서이 도구 클래스 모양을 사용하여, 다음) 메모리의 크기를 차지

기본 유형

메모리 소비의 기본 유형은 다음과 같습니다 :

 

기본 유형 메모리 크기 (단위 : 바이트)
부울 1
바이트 1
짧은
INT 4
흙손 4
8
더블 8

자바 메모리 크기의 몫 기본적인 유형이 참조 형식 공유 메모리 크기가 결정되지 않고, 지정하면 우리가 공유 참조 형 메모리 크기를 보면, 우리는 자바 단일 개체의 메모리 레이아웃으로 시작

자바 단일 개체의 메모리 레이아웃

개체 헤더

객체의 자신의 런타임 데이터 포인터 데이터 유형을 저장 : 자바에서 각 객체는 객체 헤더를 포함, 객체 헤더는 두 가지 유형의 데이터가 포함되어 있습니다

  1. 런타임 데이터 객체 자체를 저장 마크 워드 (32 비트 및 64 비트 운영 체제 및 8 바이트 길이가 4 바이트)는 다음 정보를 포함한다 :
    1. 개체 해시 코드
    2. 개체 GC 세대 시대
    3. 잠금 상태 플래그 (경량, 헤비급 잠금 장치)
    4. 스레드가 잠금을 (경량, 헤비급 잠금 장치) 보유
    5. 관련 바이어스 잠금
  2. 입력 포인터 : 객체 클래스의 메타 데이터에 대한 포인터 (32 비트 운영 체제 -> 4 바이트, 64 비트 운영 체제 -> 8 바이트 (압축 포인터가 없음), 4 바이트 (압축 개방 포인터))
    • JVM은 (객체 포인터에 따라 결정되는 클래스) 객체 클래스의 인스턴스 포인터에 의해 결정된다

따라서, 32 비트 운영 체제, Java 오브젝트의 오브젝트 헤더에 의해 점유 된 메모리 크기8字节

64 비트 운영 체제에서 :

  • 포인터가 압축에없는 경우, 개체의 크기는 머리16字节
  • 포인터 압축을 사용하도록 설정 한 경우, 개체의 크기는 머리12字节

JVM 매개 변수 UseCompressedOops압축 포인터 기능 사용 여부를 제어 할 수는 기본적으로 활성화되어, 우리는이 매개 변수를 봐주세요.

우리는 어떻게 자바 객체는 지난 점유 메모리 크기는 문제가 남아있다되었다합니까 new Point()개체가 메모리 크기 왜 차지 24字节을? 다음은입니다 Point코드 :

공용 클래스 포인트 { 
    개인 INT X; // 4字节
    전용 Y INT; // 4字节

    공공 정적 무효 메인 (문자열 []에 args) { 
        에서 System.out.println (ObjectSizeFetcher.sizeOf (새로운 포인트 ())); 
    } 
}

  이 Point클래스는 두 가지 속성이 있습니다 xy있습니다 int다음, 크기가 8 바이트에 의해 점유 재산의 두 INT 타입 4 바이트 int 형 및 공유 메모리 크기의 종류, 그래서 24 - 8 = 16字节메모리의 점유율은 무엇인가?

 

포인터는 압축 켜지지 않습니다

우리는 다음과 같은 명령을 실행하면 때 :

## 포인터 압축 켜지지 않습니다 
자바 -UseCompressedOops -javaagent : ObjectSizeFetcherAgent-1.0-SNAPSHOT.jar com.twq.Point -XX

new Point()개체의 크기는24字节

 

 거기에는 포인터 압축이 설정되지 않은, 그래서 개체의 크기가 머리 때문에이 시간입니다 16字节(: 내 컴퓨터가 64 비트 운영 체제 참고). 그것은 24 - 8 = 16字节메모리 크기에 의해 점령 객체 머리

열기 포인터 압축

우리는 다음과 같은 명령을 실행하면 때 :

## 열기 포인터 압축 
자바 -XX : + UseCompressedOops -javaagent : ObjectSizeFetcherAgent -1.0-SNAPSHOT.jar com.twq.Point

  new Point()객체의 크기 나24字节

 

 

포인터가 압축되어 있으므로 때문에이 시점에서 오브젝트 헤드의 크기이다 12字节. 그럼 24 - 8 = 16字节으로 16字节포함하는 이외에 12字节오브젝트 헤더있다 4字节많고 이는 4字节상기 정렬 심 (패딩)이다.

정렬 패딩 : 비트 정렬을 채울 필요가없는 경우 개체의 JVM 필요한 크기는 8의 정수 배수 여야합니다.

포인터 압축을 열 때, 오브젝트 헤더 크기 12字节+ 2 사이즈 속성 유형 INT 8字节= 20字节때문에, 20그것은 필요하지 8의 배수, 즉 4 바이트의 패딩을 정렬하는,24字节

자바 단일 개체의 메모리 레이아웃 요약 :

  • 정렬 패딩 +에 의해 점유 된 메모리의 크기에 의해 점유 된 속성 데이터 메모리 크기의 첫 번째 인스턴스에 의해 점유 될 + 오브젝트 메모리 크기 : 자바 오브젝트는 하나의 메모리 크기는 동일하다 공유
  • 객체 데이터 객체 헤더를 저장하면 포인터 데이터 유형과 데이터의 자신의 런타임 유형이 포함되어 있습니다. 가능하면 64 비트 운영 시스템에서, 다음 객체 헤더 크기에 의해 점유되는 메모리는 12 바이트 포인터 압축이다 열리지 다음 포인터를 압축하는 경우, 오브젝트 헤더 크기에 의해 점유되는 메모리는 16 바이트
  • 정렬 패딩 : 비트 정렬을 채울 필요가없는 경우 개체의 JVM 필요한 크기는 8의 정수 배수 여야합니다.

정적 속성 수정

우리는 Point수정 된 정적 변수, 다음 코드를 추가합니다 :

수업 포인트 {공공 
    개인 INT의 X; 
    개인 INT Y; 

    공공 정적 긴 ID = 3000L; // 추가 수정 된 정적 변수 

    공공 정적 무효 메인 (문자열 []에 args) { 
        에서 System.out.println (ObjectSizeFetcher.sizeOf (새 새로운 포인트 ())); 
    } 
}

  우리는 다음과 같은 명령을 실행하면 때 :

## 포인터 압축 켜지지 않습니다 
-UseCompressedOops -javaagent : ObjectSizeFetcherAgent-1.0-SNAPSHOT.jar com.twq.Point 자바 -XX 

## 개방 포인터 압축 
자바 -XX : + UseCompressedOops -javaagent : ObjectSizeFetcherAgent -1.0-SNAPSHOT.jar com.twq.Point

  다음과 같이하여 얻어진 결과는 :

 

 

new Point()이 개체는 메모리 크기 나 차지 24字节인스턴스에 속하지 않는, 정적 변수는 클래스에 속하는 증명을 글로벌 데이터 세그먼트에 저장, 일반적인 변수가 자바 객체의 계산에 포함 된 공간을 차지합니다.

참조 유형

각 32 비트 운영 체제에 참조 형은 4 바이트를 차지

64 비트 운영 체제에서 :

  • 열리지 않는 포인터 압축 후 8 바이트를 차지
  • 열기 포인터 압축, 다음 4 바이트를 차지

우리는라고 쓰기 RefTypeSizer읽기 클래스를 :

인격 {클래스 
} 

공용 클래스 RefTypeSizer { 
    // 이것은 참조 형 
    인격 사람 개인이; 

    공공 정적 무효 메인 (문자열 []에 인수)시 IllegalAccessException {던졌습니다 
        에서 System.out.println이 ( "새로운 RefTypeSizer () 공유 메모리 크기 개체 :"+ ObjectSizeFetcher.sizeOf (새 RefTypeSizer ()) + " 바이트"); 
    } 
}

  우리는 다음 명령을 실행 한 후 재 포장 및 :

## 포인터 압축 켜지지 않습니다 
자바 -XX : -UseCompressedOops -javaagent : ObjectSizeFetcherAgent- 1.0-SNAPSHOT.jar com.twq.RefTypeSizer

  그 결과 객체의 new RefTypeSizer()공유 메모리 크기24字节

 

 

이 시간 때문에 더 포인터 압축이 객체 헤드 크기 때문에, 설정되지이다 16字节, 타입 참조하는 Person person메모리의 비율 8字节, 그래서 크기를 추가16 + 8 = 24字节

이제, 압축 함수 포인터, 다음 명령을 열 수 있습니다 :

## 열기 포인터 압축 
자바 -XX : + UseCompressedOops -javaagent : ObjectSizeFetcherAgent -1.0-SNAPSHOT.jar com.twq.RefTypeSizer

  

그 결과 객체의 new RefTypeSizer()공유 메모리 크기16字节

 

 이 시간이 포인터 압축, 그래서 객체 헤드 크기를 설정하기 때문에 12字节, 형의 참조의 Person person메모리의 백분율을 4字节, 그래서 크기를 추가12 + 4 = 16字节

배열

64 비트 운영 체제, 객체 헤더 어레이 오브젝트는 24 바이트의 압축은 다수의 어레이 배열의 길이를 저장하기위한 추가 공간이 필요하기 때문 차지하는 종래의 객체보다는 메모리의 16 바이트를 사용 가능하게하는 포인터를 차지한다.

우리는 다음과 같이 계산된다 배열의 코드 길이를 보면 :

{클래스 공개 ArraySizer 
    공공 정적 무효 메인 (문자열 []에 args) { 
        에서 System.out.println ( "새로운 새로운 정수 [0] 주 메모리 크기"+ ObjectSizeFetcher.sizeOf (새로운 정수 [ 0]) + " 바이트" ) 
        에서 System.out.println ( "새로운 새로운 정수 주 메모리 크기 [1.]"+ ObjectSizeFetcher.sizeOf (새로운 정수 [ 1]) + " 바이트") 
        에서 System.out.println ( "새로운 새로운 정수 [2 ] 주 메모리 크기는 "+ ObjectSizeFetcher.sizeOf (새로운 정수 [ 2]) +" 바이트 ") 
        .에서 System.out.println ("새로운 새로운 정수 [3] 주 메모리 크기는 "+ ObjectSizeFetcher.sizeOf ( 새로운 정수 [3]) + "바이트") 
        에서 System.out.println ( "새로운 새로운 정수 주 메모리 크기가 [4.]"+ ObjectSizeFetcher.sizeOf (새로운 정수 [ 4]) + " 바이트"); 
    } 
}

  우리는 다음 명령을 실행 한 후 재 포장 및 :

## 포인터 압축 켜지지 않습니다 
자바 -XX : -UseCompressedOops -javaagent : ObjectSizeFetcherAgent- 1.0-SNAPSHOT.jar com.twq.ArraySizer

  다음과 같이하여 얻어진 결과이다 :

 

 

 우리가 볼 수있는 new Integer[0]크기를 24字节배열 길이가 제로이기 때문에 크기가 배열 배열 객체의 머리의 크기뿐만 아니라, 그래서, 거기에는 포인터 압축이 설정되지 않은, 그래서 배열 객체의 머리 크기가 있기 때문에 24字节, 다른 길이 배열 공유 메모리를 설명 :

 

 

  • new Integer[1]크기 : 오브젝트 헤더 24 바이트 + 1 바이트 = 8 참조 형 사이즈 32 바이트
  • new Integer[2]크기 : 오브젝트 헤더 24 바이트 + 2 바이트 참조 형 사이즈 16 바이트 = 40
  • new Integer[3]크기 : 오브젝트 헤더 바이트 + 24 바이트 3 참조 형 사이즈 24 바이트 = 48
  • new Integer[4]크기 : 오브젝트 헤더 24 바이트 + 4 바이트 참조 형 사이즈 32 바이트 = 56
  • new Integer[]{2, 3, 4, 5}비트 크기 : new Integer[4]56 바이트 + 4 * (정수 정수 객체 헤더 크기 + 16 속성 유형 INT 바이트 + 4 바이트 4 바이트 정렬 심) = 152 바이트의 크기

그리고 우리가 포인터 압축을 설정, 다음 명령을 실행합니다 :

## 열기 포인터 압축 
자바 -XX : + UseCompressedOops -javaagent : ObjectSizeFetcherAgent -1.0-SNAPSHOT.jar com.twq.ArraySizer

  다음과 같이하여 얻어진 결과이다 :

 

 

우리가 볼 수있는 new Integer[0]크기를 16字节배열 길이가 제로이기 때문에 크기가 배열 배열 객체의 머리의 크기 때문에,뿐만 아니라 포인터 압축을 열어, 그래서 배열 객체의 머리 크기가 있기 때문에 16字节, 다른 길이 배열 공유 메모리를 설명 :

  • new Integer[1]크기 : 물체 16 바이트 헤더가 1 바이트 + 4 참조 배향 형 크기가 4 바이트 = 24 바이트가 추가 +
  • new Integer[2]크기 : 8 바이트 객체 헤더 16 바이트 + 2 바이트 기준 글자 크기 = 24
  • new Integer[3]크기 : 오브젝트 참조 형 크기의 처음 16 바이트 + 3 + 4 = 12 바이트 정렬 된 바이트는 32 바이트를 추가
  • new Integer[4]크기 : 오브젝트 헤더 16 바이트 + 4 바이트 참조 형 사이즈 16 바이트 = 32
  • new Integer[]{2, 3, 4, 5}비트 크기 : new Integer[4]32 바이트 + 4 *의 크기 (Integer 객체 헤더 바이트는 4 바이트의 12 + 정수형 INT 속성 사이즈) = 96 바이트

개요

자바 단일 개체의 메모리 레이아웃 요약 :

  • 정렬 패딩 +에 의해 점유 된 메모리의 크기에 의해 점유 된 속성 데이터 메모리 크기의 첫 번째 인스턴스에 의해 점유 될 + 오브젝트 메모리 크기 : 자바 오브젝트는 하나의 메모리 크기는 동일하다 공유
  • 객체 데이터 객체 헤더를 저장하면 포인터 데이터 유형과 데이터의 자신의 런타임 유형이 포함되어 있습니다. 가능하면 64 비트 운영 시스템에서, 다음 객체 헤더 크기에 의해 점유되는 메모리는 12 바이트 포인터 압축이다 열리지 다음 포인터를 압축하는 경우, 오브젝트 헤더 크기에 의해 점유되는 메모리는 16 바이트
  • 정렬 패딩 : 비트 정렬을 채울 필요가없는 경우 개체의 JVM 필요한 크기는 8의 정수 배수 여야합니다.
  • 글로벌 데이터 세그먼트에 저장된 인스턴스에 속하지 않는 클래스에 속하는 정적 변수는 일반 변수는 자바 오브젝트에 의해 점유되는 공간을 계산에 포함
  • 각 32 비트 운영 체제에 참조 타입은 64 비트 운영 체제에서 4 바이트를 차지한다 :
    • 열리지 않는 포인터 압축 후 8 바이트를 차지
    • 열기 포인터 압축, 다음 4 바이트를 차지
  • 64 비트 운영 체제, 객체 헤더 어레이 오브젝트는 24 바이트의 압축은 다수의 어레이 배열의 길이를 저장하기위한 추가 공간이 필요하기 때문 차지하는 종래의 객체보다는 메모리의 16 바이트를 사용 가능하게하는 포인터를 차지한다.

위에서 하나의 간단한 자바 오브젝트는 복잡한 계산이다 자바 점유 된 메모리의 크기는 공유 메모리 크기 m 개체

추천

출처www.cnblogs.com/tesla-turing/p/11487785.html