10 장 개체 인스턴스화 메모리 레이아웃 및 액세스 위치

10 장 개체 인스턴스화 메모리 레이아웃 및 액세스 위치

Shang Silicon Valley의 Song Hongkang이 설명하는 JVM : bilibili 링크

1 개체 인스턴스화

  • 인터뷰 질문들
    • 메이 투안
      • 객체는 JVM에 어떻게 저장됩니까?
      • 개체 헤더 정보에는 무엇이 있습니까?
    • 앤트 파이낸셜
      • 두 번째 측면 : 자바 객체 헤더에는 무엇이 있습니까?

여기에 사진 설명 삽입

여기에 사진 설명 삽입


  • 개체를 만드는 단계

    1. 객체에 해당하는 클래스가로드, 링크, 초기화되었는지 확인

      가상 머신이 새 명령어를 발견하면 먼저이 명령어의 매개 변수가 Metaspace의 상수 풀에서 클래스의 심볼 참조를 찾을 수 있는지 확인하고이 심볼 참조가 나타내는 클래스가로드되고, 구문 분석되고, 초기화되었습니다. (즉, 메타 정보가 존재하는지 여부를 확인하는 것입니다.) 그렇지 않은 경우 상위 위임 모드에서 현재 클래스 로더를 사용하여 ClassLoader + 패키지 이름 + 클래스 이름 Key가있는 해당 .class 파일을 찾습니다. 파일이 발견되지 않으면 ClassNotFoundException이 발생하고 발견되면 클래스가로드되고 해당 Classs 객체가 생성됩니다.

    2. 개체에 대한 메모리 할당

      먼저 개체가 차지하는 공간을 계산 한 다음 새 개체의 힙에 메모리 블록을 할당합니다. 인스턴스 멤버 변수가 참조 변수 인 경우 크기가 4 바이트 인 참조 변수 공간 만 할당하면됩니다.

      • 메모리가 규칙적이면 포인터 충돌을 사용하십시오.

        메모리가 규칙적인 경우 가상 머신은 Bump The Pointer를 사용하여 개체에 대한 메모리를 할당합니다. 사용 된 모든 메모리가 한쪽에 있고 여유 메모리가 다른쪽에 있음을 의미합니다. 중간에 경계 지점을 나타내는 포인터가 있습니다. 메모리를 할당하는 것은 포인터를 자유쪽으로 이동하는 것입니다. 물체의 크기와 같은 거리. 가비지 수집기가 표시 압축 알고리즘을 기반으로 Serial 및 ParNew를 선택하면 가상 머신은이 할당 방법을 사용합니다. 일반적으로 콤팩트 프로세스의 콜렉터를 사용하는 경우 포인터 충돌이 사용됩니다.

      • 메모리가 일정하지 않은 경우 가상 머신은 목록을 유지하고 사용 가능한 목록을 사용하여 할당해야합니다.

        메모리가 규칙적이지 않으면 사용 된 메모리와 사용되지 않은 메모리가 서로 인터리브되면 가상 머신은 사용 가능한 목록 방법을 사용하여 개체에 대한 메모리를 할당합니다. 이는 가상 머신이 사용 가능한 메모리 블록을 기록하기 위해 목록을 유지한다는 것을 의미하며, 재배포 할 때 목록에서 개체 인스턴스를 분할하고 목록의 내용을 업데이트 할 수있는 충분한 공간을 찾아야합니다. 이 할당 방법을 "Free List"라고합니다.

        참고 : 할당 방법의 선택은 Java 힙이 일반인지 여부에 따라 결정되고 Java 힙이 일반인지 여부는 사용되는 가비지 수집기에 압축 기능이 있는지 여부에 따라 결정됩니다.

    3. 동시성 보안 문제 처리

      메모리 공간을 할당 할 때 또 다른 문제는 새로운 객체의 스레드 안전성을 제때에 보장하는 것입니다. 객체 생성은 매우 빈번한 작업이며 가상 머신은 동시성 안전성 문제를 해결해야합니다. 가상 머신은 두 가지 방법을 사용하여 동시성 보안 문제를 해결합니다.

      • CAS (비교 및 스왑) 실패 재시도, 영역 잠금 : 포인터 업데이트 작업의 원 자성을 보장합니다.
      • 메모리 할당에 따른 TLAB 오른쪽 작업은 각 스레드가 Java에서 미리 할당 된 힙 메모리의 작은 조각 인 스레드 로컬 할당 버퍼 (TLAB, Thread Local Allocation Buffer) , 가상 머신인지 여부 에 따라 서로 다른 스레드 공간으로 나뉩니다. TLAB 사용 여부는 -XX : +/- UseTLAB 매개 변수로 설정할 수 있습니다.
    4. 할당 된 공간 초기화

      메모리 할당이 끝나면 가상 머신에서 할당 한 메모리 공간이 0 값으로 초기화됩니다 (개체 헤더 제외). 이 단계는 객체의 인스턴스 필드를 초기 값을 할당하지 않고 Java 코드에서 직접 사용할 수 있으며 프로그램이 이러한 필드의 데이터 유형에 해당하는 0 값에 액세스 할 수 있도록합니다.

    5. 개체의 개체 헤더 설정

      객체의 클래스 (즉, 클래스의 메타 데이터 정보), 객체의 HashCode, 객체의 GC 정보, 잠금 정보 및 기타 데이터를 객체의 객체 헤더에 저장합니다. 이 프로세스의 특정 설정은 JVM 구현에 따라 다릅니다.

    6. 초기화 할 init 메서드를 실행합니다.

      Java 프로그램의 관점에서 초기화는 공식적으로 시작되었습니다. 멤버 변수를 초기화하고, 인스턴스화 된 코드 블록을 실행하고, 클래스의 생성 메서드를 호출하고, 힙에있는 개체의 첫 번째 주소를 참조 변수에 할당합니다.

      따라서 일반적으로 말하면 (바이트 코드 다음에 invokespecial 명령어가 오는지 여부에 따라 결정됨) 실행 메소드는 새 명령어 다음에 이어집니다. 객체는 프로그래머의 희망에 따라 초기화되므로 진정으로 사용 가능한 객체가 완전히 생성됩니다.

2 개체의 메모리 레이아웃

  • 생성 된 개체가 힙에 포함하는 콘텐츠는 무엇입니까?

    여기에 사진 설명 삽입

    모든 객체가 유형 포인터를 저장하는 것은 아닙니다.

  • /**
     * 测试对象实例化的过程
     *  ① 加载类元信息 - ② 为对象分配内存 - ③ 处理并发问题  - ④ 属性的默认初始化(零值初始化)
     *  - ⑤ 设置对象头的信息 - ⑥ 属性的显式初始化、代码块中初始化、构造器中初始化
     *
     *
     *  给对象的属性赋值的操作:
     *  ① 属性的默认初始化 - ② 显式初始化 / ③ 代码块中初始化 - ④ 构造器中初始化
     */
    
    public class Customer{
          
          
        int id = 1001;  // ② 显式初始化
        String name;
        Account acct;
    
        {
          
          
            name = "匿名客户";  // ③ 代码块中初始化
        }
        public Customer(){
          
          
            acct = new Account();  // ④ 构造器中初始化
        }
    
    }
    class Account{
          
          
    
    }
    
    public class CustomerTest {
          
          
        public static void main(String[] args) {
          
          
            Customer cust = new Customer();
        }
    }
    

    여기에 사진 설명 삽입

3 개체의 액세스 위치

여기에 사진 설명 삽입

  • JVM은 스택 프레임의 개체 참조를 통해 내부 개체 인스턴스에 어떻게 액세스합니까?

    • 스택에서 참조로 액세스

    여기에 사진 설명 삽입

  • 두 가지 방법의 개체 액세스

    • 액세스 처리

      여기에 사진 설명 삽입

      • 장점 : GC 후에 핸들 풀의 주소 만 변경하면됩니다.
      • 단점 : 낮은 액세스 효율성, 인스턴스 데이터 및 메타 데이터에 대한 액세스에는 전송이 필요함
    • 직접 포인터 (핫스팟에서 채택)

      여기에 사진 설명 삽입

      장점 : 높은 액세스 효율성, 한 번에 인스턴스 데이터에 액세스

      단점 : GC 후에 가상 머신 스택의 로컬 변수 테이블에있는 참조 주소를 변경해야합니다.

추천

출처blog.csdn.net/weixin_42638946/article/details/113646905