초보 자 자바 대상 메모리 구성

11711 단어 Java신출내기대상
Java 개체 메모리 구성
오늘 은 추상 적 인 것 인 대상 머리 를 말씀 드 리 겠 습 니 다.왜냐하면 저 는 공부 하 는 과정 에서 많은 부분 이 대상 머리의 지식 점 과 관련 된 것 을 발 견 했 기 때 문 입 니 다.예 를 들 어 JDK 중의 synchronized 자물쇠 최적화 와 JVM 에서 대상 의 연령 업그레이드 등 입 니 다.이러한 지식의 원 리 를 깊이 이해 하고 대상 헤드 의 개념 을 이해 하 는 것 이 필요 하 며,synchronized 원리 와 JVM 지식 을 뒤에서 공유 할 때 준비 할 수 있다.
대상 메모리 구성
자바 에서 new 키 워드 를 통 해 인 스 턴 스 대상 을 만 듭 니 다.대상 은 메모리 더미 에 저장 하고 메모리 주 소 를 할당 합 니 다.다음 과 같은 문 제 를 생각해 보 셨 습 니까?
  • 이 실례 대상 은 어떤 형태 로 메모리 에 존재 합 니까?
  • 하나의 Object 대상 이 메모리 에서 얼마나 많이 차지 합 니까?
  • 대상 의 속성 은 어떻게 메모리 에서 분 배 됩 니까?

  • JVM 에서 자바 대상 이 더미 에 저 장 될 때 다음 세 부분 으로 구 성 됩 니 다.
  • 대상 헤드(object header):쌓 인 대상 의 구조,유형,GC 상태,동기 상태 와 표지 해시 코드 에 대한 기본 정 보 를 포함한다.자바 대상 과 vm 내부 대상 은 모두 공 통 된 대상 헤더 형식 을 가지 고 있 습 니 다.
  • 인 스 턴 스 데이터(Instance Data):주로 클래스 의 데이터 정보,부모 류 의 정보,대상 필드 속성 정 보 를 저장 합 니 다.
  • 정렬 충전(Padding):바이트 정렬 을 위해 채 워 진 데 이 터 는 필수 가 아 닙 니 다.

  • 대상 헤드
    우 리 는Hotspot 공식 문서에서 그것 의 설명 을 찾 을 수 있다(아래 그림).이 를 통 해 자바 대상 과 가상 컴퓨터 내부 대상 이 모두 가지 고 있 는 공 통 된 형식 으로 두 글자(컴퓨터 용어)로 구성 되 어 있 음 을 알 수 있다.또한 대상 이 자바 배열 이 라면 대상 머리 에 배열 의 길 이 를 기록 하 는 데 사용 되 는 데이터 가 있어 야 합 니 다.가상 머 신 은 일반 자바 대상 의 메타 데이터 정 보 를 통 해 자바 대상 의 크기 를 확인 할 수 있 지만 배열 의 메타 데이터 에서 배열 의 크기 를 정할 수 없 기 때 문 입 니 다.

    그 안에 대상 머리 는 두 글자 로 구성 되 어 있 는데 이 두 글 자 는 무엇 입 니까?우 리 는 위 에 있 는 Hotspot 공식 문서 에서 위 를 보면 다른 두 명사 의 정의 해석 이 있 는데 그것 이 바로 mark word 와 klass pointer 이다.

    대상 의 머리 에 있 는 두 글 자 를 발견 할 수 있 습 니 다.첫 번 째 글 자 는 mark word 이 고 두 번 째 글 자 는 klass pointer 입 니 다.
    Mark Word
    대상 자체 의 운행 시 데 이 터 를 저장 하 는 데 사 용 됩 니 다.예 를 들 어 하 시 코드(HashCode),GC 세대 별 연령,잠 금 상태 표지,스 레 드 가 가지 고 있 는 자물쇠,편향 스 레 드 ID,편향 시간 스탬프 등 입 니 다.
    Mark Word 는 32 비트 JVM 중 길이 가 32bit 이 고 64 비트 JVM 중 길이 가 64bit 입 니 다.우 리 는openjdk 의 소스 패키지,대응 경로/openjdk/hotspot/src/share/vm/oops,Mark Word 가 C++에 대응 하 는 코드markOop.hpp를 열 었 습 니 다.주석 에서 그들의 구성 을 볼 수 있 습 니 다.본 고의 모든 코드 는 Jdk 1.8 를 바탕 으로 합 니 다.

    Mark Word 는 잠 금 상태 에 따라 저 장 된 내용 이 다 르 며 32 비트 JVM 에 이렇게 저 장 됩 니 다.

    64 비트 JVM 에 이렇게 저장 되 어 있 습 니 다.

    이들 은 자릿수 별 JVM 에서 길이 가 다 르 지만 기본 구성 내용 은 일치한다.
  • (lock):잠 금 상 태 를 구분 하고 11 시 에 대상 이 GC 회수 상 태 를 기다 리 고 마지막 2 자리 잠 금 표지(11)만 유효 하 다 고 표시 한다.
  • biased_lock:자물쇠 의 편향 여 부 는 자물쇠 와 편향 자물쇠 가 없 는 자물쇠 표지 가 모두 01 이기 때문에 구분 할 수 없다.여기 서 한 사람의 편향 자물쇠 표지 위 치 를 도입 한다.
  • (age):는 대상 이 GC 에 당 하 는 횟수 를 나타 내 는데 이 횟수 가 한도 값 에 도달 하면 대상 이 옛날 로 이전 된다.
  • hashcode(hash):운행 기간 에 System.identity HashCode()를 호출 하여 계산 을 지연 시 키 고 결 과 를 여기에 할당 합 니 다.대상 이 자 물 쇠 를 추가 하면 계 산 된 결과 31 비트 가 부족 합 니 다.편향 자물쇠,경 량 자물쇠,중량 자물쇠,hashcode 는 Monitor 로 전 이 됩 니 다.
  • ID(JavaThread):편향 모드 일 때 특정한 스 레 드 가 대상 을 가지 고 있 을 때 대상 은 이 스 레 드 의 ID 로 설정 된다.다음 작업 에서 자 물 쇠 를 가 져 오 는 동작 을 시도 할 필요 가 없습니다.
  • epoch:CAS 잠 금 작업 과정 에서 편향 적 인 표 지 는 대상 이 어느 잠 금 을 선 호 하 는 지 나타 낸다.
  • ptr_to_lock_record:경량급 잠 금 상태 에서 스 택 에 기 록 된 지침 을 가리킨다.잠 금 획득 이 경쟁 이 없 을 때 JVM 은 OS 가 서로 배척 하 는 것 이 아니 라 원자 조작 을 사용 합 니 다.이런 기술 을 경량급 잠 금 이 라 고 한다.가 벼 운 잠 금 상태 에서 JVM 은 CAS 작업 을 통 해 대상 의 제목 글자 에 잠 금 기록 을 가리 키 는 지침 을 설정 합 니 다.
  • ptr_to_heavyweight_monitor:헤비급 잠 금 상태 에서 대상 모니터 Monitor 를 가리 키 는 지침.두 개의 서로 다른 스 레 드 가 같은 대상 에서 동시에 경쟁 할 경우 경량급 잠 금 을 Monitor 로 업그레이드 하여 기다 리 는 스 레 드 를 관리 해 야 합 니 다.헤비급 잠 금 상태 에서 JVM 은 대상 의 ptrto_heavyweight_Monitor 는 Monitor 를 가리 키 는 지침 을 설정 합 니 다.
  • Klass Pointer
    즉,유형 지침 은 대상 이 메타 데 이 터 를 가리 키 는 지침 입 니 다.가상 컴퓨터 는 이 지침 을 통 해 이 대상 이 어떤 종류의 인 스 턴 스 인지 확인 합 니 다.
    인 스 턴 스 데이터
    대상 에 속성 필드 가 있 으 면 데이터 정보 가 있 습 니 다.대상 이 속성 필드 가 없 으 면 데이터 가 없습니다.필드 유형 에 따라 서로 다른 바이트,예 를 들 어 boolean 유형 은 1 개의 바이트,int 유형 은 4 개의 바이트 등 을 차지한다.
    데이터 정렬
    대상 은 정렬 된 데이터 가 있 을 수도 있 고 없 을 수도 있다.기본 적 인 상황 에서 자바 가상 컴퓨터 더미 의 시작 주 소 는 8 의 배수 로 맞 춰 야 합 니 다.대상 이 8N 바이트 가 되 지 않 으 면 대상 헤더 와 인 스 턴 스 데이터 가 메모 리 를 차지 한 후 남 은 공간 크기 를 보충 해 야 합 니 다.대상 헤드 와 인 스 턴 스 데이터 가 JVM 이 할당 한 메모리 공간 을 가득 채 웠 다 면 정렬 충전 을 하지 않 아 도 됩 니 다.
    모든 대상 이 할당 하 는 바이트 의 총 SIZE 수 요 는 8 의 배수 이 며,앞의 대상 헤드 와 인 스 턴 스 데이터 가 차지 하 는 총 SIZE 가 요 구 를 만족 시 키 지 못 하면 데이터 정렬 을 통 해 채 워 집 니 다.
    데 이 터 를 왜 맞 춰 야 합 니까?필드 메모리 정렬 의 한 가지 이 유 는 같은 CPU 의 캐 시 줄 에 만 필드 를 나타 내 는 것 입 니 다.필드 가 정렬 되 지 않 으 면 캐 시 줄 을 뛰 어 넘 는 필드 가 생 길 수 있 습 니 다.즉,이 필드 의 읽 기 는 두 개의 캐 시 줄 을 교체 해 야 할 수도 있 고,이 필드 의 저장 소 는 두 개의 캐 시 줄 을 동시에 오염 시 킬 수도 있다.이 두 가지 상황 은 프로그램의 집행 효율 에 있어 서 모두 불리 하 다.사실 그 충전 의 최종 목적 은 컴퓨터 의 효율 적 인 주 소 를 찾기 위 한 것 이다.
    이로써 우 리 는 대상 이 메모리 에 쌓 여 있 는 전체적인 구조 구 조 를 알 게 되 었 다.아래 그림 과 같다.

    Talk is cheap, show me code
    개념 적 인 것 은 추상 적 인 것 이다.너 는 그것 이 이렇게 구성 되 었 다 고 말 하 는데 정말 이 냐?공 부 는 의심 하 는 태 도 를 가 져 야 한다.모든 이론 과 개념 은 자신 이 실증 하고 실천 한 후에 야 받 아들 일 수 있다.다행히 openjdk 는 우리 에 게 도구 패 키 지 를 제공 하여 대상 의 정보 와 가상 컴퓨터 의 정 보 를 얻 을 수 있 습 니 다.우 리 는 jol-core 의존 만 도입 하면 됩 니 다.다음 과 같 습 니 다.
    
    <dependency>
      <groupId>org.openjdk.jol</groupId>
      <artifactId>jol-core</artifactId>
      <version>0.8</version>
    </dependency>
    jol-core 에서 자주 사용 하 는 세 가지 방법
  • ClassLayout.parseInstance(object).toPrintable():대상 내부 정 보 를 조회 합 니 다.
  • GraphLayout.parseInstance(object).toPrintable():대상 의 외부 정 보 를 조회 하고 인용 대상 을 포함한다.
  • GraphLayout.parseInstance(object).totalSize():대상 의 총 크기 를 봅 니 다.
  • 일반 대상
    단순화 하기 위해 서,우 리 는 복잡 한 대상 을 사용 하지 않 고,스스로 클래스 D 를 만 들 고,먼저 속성 이 없 는 필드 를 볼 때
    
    public class D {
    }
    jol-core api 를 통 해 대상 의 내부 정 보 를 인쇄 합 니 다.
    
    public static void main(String[] args) {
        D d = new D();
        System.out.println(ClassLayout.parseInstance(d).toPrintable());
    }
    마지막 인쇄 결 과 는?

    이 몇 개의 명 어 를 볼 수 있 는데,그것들의 의 미 는 각각
  • OFFSET、SIZE、TYPE DESCRIPTION、VALUE :주소 오프셋,단위 바이트;
  • OFFSET:사용 하 는 메모리 크기,단 위 는 바이트 입 니 다.
  • SIZE:유형 설명,그 중에서 object header 는 대상 머리 입 니 다.
  • TYPE DESCRIPTION:메모리 에 현재 저 장 된 값,바 이 너 리 32 비트 에 대응 합 니 다.

  • d 대상 인 스 턴 스 는 모두 16byte 를 차지 하고 대상 헤드(object header)는 12byte(96bit)를 차지 하 는 것 을 볼 수 있 습 니 다.그 중에서 mark word 는 8byte(64bit)를 차지 하고 klass pointe 는 4byte 를 차지 하 며 나머지 4byte 는 정렬 되 어 있 습 니 다.
    여 기 는 기본적으로 지침 압축 을 열 었 기 때문에 대상 의 머리 는 12byte 를 차지 하고 구체 적 인 지침 압축 의 개념 은 여기 서 더 이상 논술 하지 않 으 며 관심 이 있 는 독 자 는 스스로 찾 아 볼 수 있다공식 문서.jdk 8 버 전 은 기본적으로 포인터 압축 을 엽 니 다.vm 매개 변 수 를 설정 하여 포인터 압축 을 닫 을 수 있 습 니 다.VALUE
    포인터 압축 을 닫 고 대상 의 메모리 레이아웃 을 다시 인쇄 하면 전체 SIZE 가 커 진 것 을 발견 할 수 있 습 니 다.아래 그림 에서 볼 수 있 듯 이 대상 머리 가 사용 하 는 메모리 크기 는 16byte(128 bit)로 변 했 습 니 다.그 중에서 mark word 는 8byte 를 차지 하고 klass pointe 는 8byte 를 차지 하 며 정렬 되 지 않 고 채 워 집 니 다.

    포인터 압축 을 켜 면 대상 의 메모리 사용 을 줄 일 수 있 습 니 다.두 번 인쇄 된 D 개체 레이아웃 정 보 를 보면 포인터 압축 을 닫 을 때 대상 헤드 의 SIZE 에 4byte 가 추 가 됩 니 다.여 기 는 D 대상 이 속성 이 없 기 때문에 독자 가 몇 개의 속성 필드 를 추가 해 볼 수 있 습 니 다.그러면 SIZE 가 증가 하 는 것 을 뚜렷하게 발견 할 수 있 습 니 다.따라서 지침 압축 을 켜 면 이론 적 으로 50%의 메모 리 를 절약 할 수 있다.jdk 8 및 이후 버 전 은 기본적으로 포인터 압축 을 열 었 습 니 다.설정 할 필요 가 없습니다.
    배열 개체
    위 에서 사용 하 는 것 은 일반 대상 입 니 다.배열 대상 의 메모리 구 조 를 살 펴 보고 어떤 차이 점 이 있 는 지 비교 해 보 겠 습 니 다.
    
    public static void main(String[] args) {
        int[] a = {1};
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
    인쇄 된 메모리 레이아웃 정 보 는 다음 과 같 습 니 다.

    이 때 전체 SIZE 는 총 24byte 이 고 대상 의 머리 는 16byte 이다.그 중에서 Mark Work 는 8byte 를 차지 하고 Klass Point 는 4byte 를 차지 하 며 array length 는 4byte 를 차지한다.그 안에 int 형식의 1 만 있 기 때문에 배열 대상 의 인 스 턴 스 데 이 터 는 4byte 를 차지 하고 나머지 정렬 충전 은 4byte 를 차지한다.
    총결산
    이상 의 내용 을 통 해 우 리 는 대상 이 메모리 에 있 는 구 조 를 알 게 되 었 고 대상 의 메모리 구조 와 대상 헤드 의 개념 을 알 게 되 었 다.특히 대상 헤드 의 Mark Word 의 내용 은 synchronize 자물쇠 최적화 와 JVM 쓰레기 회수 연령 대 를 후속 적 으로 분석 할 때 큰 역할 을 할 것 이다.
    JVM 에 서 는 대상 이 Suvivor 에서 한 번 씩 MinorGC 를 견 딜 때마다 나이 가 1 씩 늘 어 나 고 나이 가 어느 정도 늘 어 나 면 옛날 로 승진 하 는 것 을 기억 하 십 니까?이 횟수 는 기본적으로 15 살 입 니 다.왜 15 살 인지 생각해 본 적 이 있 습 니까?마크 워드 에서 대상 의 세대 나 이 를 표시 하 는 공간 이 4bit 인 것 을 발견 할 수 있 는데 4bit 가 표시 할 수 있 는 최대 수 는-XX:-UseCompressedOops이다.
    이 글 은 여기까지 입 니 다.당신 에 게 도움 을 줄 수 있 기 를 바 랍 니 다.또한 당신 이 우리 의 더 많은 내용 에 관심 을 가 져 주 기 를 바 랍 니 다!

    좋은 웹페이지 즐겨찾기