BiBi - JVM - 10 - VM 바이트

6299 단어
From: Java 가상 머신 이해
  • 디렉터리 비비-JVM-0-개편 비비-JVM-1-자바 메모리 영역 비비-JVM-2-대상 비비-JVM-3-쓰레기 수집 알고리즘 비비-JVM-4-HotSpot JVM 비비-JVM-5-쓰레기 수거기비-JVM-6-회수 전략 비비-JVM-7-자바 클래스 파일 구조 비비-JVM-8-클래스 로딩 메커니즘 비-JVM-9-클래스 로더 비비-JVM-10-가상 컴퓨터 비비비-Bi-JVM 최적화 컴파일기 비비-비비-비비-12-JVM 최적화Bi - JVM-13-동시
  • 물리적 시스템: 실행 엔진은 프로세서, 하드웨어, 지령집과 운영체제 차원에서 직접 세워진다.가상 머신: 실행 엔진은 스스로 실현하고 스스로 지령집을 제정할 수 있다.

    1. 잔정


    잔정은 가상 기기 방법 호출 과정의 데이터 구조로 주로 국부 변수표, 조작 수잔, 동적 링크, 방법 반환 주소 등을 포함한다.코드를 컴파일할 때 창고에 얼마나 큰 국부 변수표가 필요한지, 얼마나 깊은 조작 창고가 모두 확정되었는지, 그리고 방법표의Code 속성에 기록되었는지[그 중에서 max loclas는 국부 변수표의 최대 용량을 대표한다]. 따라서 한 창고에 얼마나 많은 메모리를 분배해야 하는지 프로그램 운행기 변수 데이터의 영향을 받지 않는다.
  • 국부 변수표
  • 저장 방법 매개 변수와 방법 내부에 정의된 국부 변수입니다.국부 변수표의 용량은 [변수 슬롯, Slot]을 최소 단위로 하고 한 Slot은 32비트 이내의 데이터 형식을 저장할 수 있다.롱과 더블 64비트의 데이터는 높은 위치에서 정렬하는 방식으로 두 개의 연속적인 슬로트 공간을 분배한다.방법이 실행될 때 가상 기기는 국부 변수표를 사용하여 [파라미터 값]에서 [파라미터 변수 목록]까지의 전달을 완성한다.
    Slot 재사용은 쓰레기 재활용에 영향을 미칩니다.
    // : b , b 。
    public static void main(String[] args) {
      byte[] b = new byte[1024 * 1024 * 64];
      System.gc();
    }
    
    // : Slot ,b 
    public static void main(String[] args) {
      {
        byte[] b = new byte[1024 * 1024 * 64];
      }
      System.gc();
    }
    
    // :b 
    public static void main(String[] args) {
      {
        byte[] b = new byte[1024 * 1024 * 64];
      }
      int a = 0;
      System.gc();
    }
    

    위의 세 가지 방식 중 b가 회수될 수 있는 근본적인 원인은 국부 변수표의 Slot에 b수 그룹 대상의 인용이 존재하는지 여부입니다.방식2는 비록 b의 역할 영역을 벗어났지만 그 후에 국부 변수표에 대한 읽기와 쓰기 작업이 없었다. b가 원래 차지했던 Slot은 다른 변수에 의해 복용되지 않았기 때문에 GC Roots의 일부분인 국부 변수표는 여전히 그에 대한 관련성을 유지하고 있다.[수동으로 b=null을 설정하여 회수 효과를 얻을 수도 있다] 단, 방식 2, JIT 컴파일을 거친 후 회수할 수 있기 때문에 방식 3처럼 처리할 필요가 없다.
    참고: 로컬 변수에는 기본값이 없습니다.
  • 운영 스택
  • 컴파일할 때 최대 깊이를 코드 속성의 max 에 쓰기Stacks 데이터 항목에서두 잔정은 가상 기기 요소로서 완전히 독립적이다.그러나 대부분의 가상 기기의 실현에서 최적화 처리를 해서 두 창고의 일부분을 중첩시킨다. 이렇게 하면 방법이 호출될 때 일부 데이터를 공용할 수 있고 추가 파라미터 복제 전달을 할 필요가 없다.
    자바 가상기는 창고를 기반으로 하는 실행 엔진으로 그 중에서 가리키는 창고는 [조작 창고]이다.
  • 동적 연결
  • 모든 잔정은 지향 운행 시 [상량지]에서 이 잔정이 속한 방법의 인용을 포함하고 이 인용을 가진 것은 방법 호출 과정에서의 동적 연결을 지원하기 위한 것이다.Class 파일의 상수 탱크에는 대량의 [기호 인용]이 존재하고 바이트 코드의 방법 호출 명령은 상수 탱크에서 방법을 가리키는 기호 인용을 매개 변수로 한다.이러한 기호 인용의 일부분은 클래스가 불러오는 단계나 처음 사용할 때 직접 인용으로 전환된다. 이런 전환을 [정적 해석, 예를 들어 정적 방법, 사유 방법, 실례 구조기, 부류 방법이라고 한다. 즉, 컴파일링 기간은 알 수 있고 운행 기간은 변할 수 없다]라고 한다.또 다른 부분은 매번 운행 기간에 직접 인용으로 전환되는데 이런 전환을 [동적 연결]이라고 부른다.

    2. 방법 호출


    invokestatic invokespecial invokevirtual invointerface invokedynamic [분배 논리는 가상 머신에 의해 결정되는 것이 아니라 프로그래머에 의해 결정됩니다]
    Class 파일을 컴파일하는 과정에서 전통적인 컴파일에서의 연결 절차를 포함하지 않습니다. 모든 방법이 Class 파일에 저장된 것은 기호 인용일 뿐 실제 실행할 때 메모리 레이아웃의 입구 주소가 아닙니다.이 기능은 클래스가 불러오는 동안 또는 실행 중에 목표 방법의 직접 인용을 확정하여 동적 확장 능력을 더욱 강하게 할 수 있습니다.
    정적 해석의 바이트 코드 명령: invokestatic, invokespecial [실례 구조기, 개인 방법, 부류 방법]과final에 의해 수식된 방법.클래스를 불러올 때 기호 인용을 직접 인용으로 해석합니다.
  • 정적 분배 [중재 대상]
  • public class StaticDispatch {
      static abstract class Human {
      }
    
      static class Man extends Human {
      }
    
      public void say(Human obj) {
        System.out.println("human");
      }
    
      public void say(Man obj) {
        System.out.println("man");
      }
    
      public static void main(String[] args) {
        Human man = new Man();
        StaticDispatch st = new StaticDispatch();
        st.say(man); //human
      }
    }
    

    출력 결과는:human입니다.Human man = new Man()에서 Human은 변수의 [정적 유형]이다.Man은 변수의 [실제 유형]입니다.정적 유형은 컴파일링 기간에 알 수 있지만 실제 유형은 실행 기간에 알 수 있습니다.리셋은 매개 변수의 정적 형식을 통해 하는 것이지 실제 형식을 통해 판단하는 것이 아니다.그래서 컴파일 단계에서 어떤 재부팅 버전을 사용할지 결정했습니다.
  • 동적분파[다태적 덮어쓰기]
  • 운행 기간에 [실제 유형] 확정 방법에 따라 버전을 집행하는 분배 과정을 동적 분배라고 한다.유형 방법 구역에 [허방법표]를 세우고 허방법표를 사용하여 각 방법의 실제 입구를 확정한다.같은 서명을 가진 방법은 부류, 자류의 허방법표에 모두 같은 색인 번호를 가지고 있다.

    3. 동적 언어 지원


    JDK7 바이트 코드 명령은 동적 형식 언어를 지원하기 위해 [invokedynamic 명령]을 집중적으로 추가하고 JDK8의 Lambda 표현식을 준비합니다.
    동적 언어 관건 특징: 유형 검사는 컴파일러가 아니라 실행 중입니다.특징: 변수는 유형이 없고 변수 값만 유형이 있습니다.자바 가상기의 경우 정적 언어와 동적 언어 [Groovy, JRuby]를 동시에 지원할 수 있다.
    invokestatic, invokespecial, invokevirtual, invointerface의 첫 번째 매개 변수는 모두 [호출된 방법의 기호 인용]이기 때문에 이 기호 인용은 컴파일할 때 발생하고 동적 언어는 실행 기간에만 수신자의 유형을 확정할 수 있다. 이런 하부 문제는 가상 기기 차원에서만 해결하는 것이 가장 적합하기 때문에 invokedynamic 명령이 탄생했다.
    java.lang.invoke 패키지는 이전에 단순히 기호 인용에 의존하여 호출된 목표 방법을 확정하는 것 외에 새로운 동적 목표 방법 메커니즘을 제공했다. 이를 [MethodHandle, 함수 지침과 유사하다]라고 부른다.
    MethodHandler 효과는 Reflection 반사와 유사하게 모두 아날로그 방법으로 호출된다. 그 차이는 다음과 같다. 1) Reflection은 아날로그 자바 코드 차원에서 호출되고 MethodHandler는 아날로그 바이트 차원에서 호출된다.2) Reflection은 중량급으로 방법의 서명, 설명자, 방법 속성표 등을 포함한다.반면 MethodHandler는 경량급으로 이 방법을 실행하는 정보만 포함한다.3) Reflection은 자바 언어만을 위한 것이고 MethodHandler는 모든 자바 가상 기기의 언어에 서비스를 제공할 수 있다.
  • 문제: 슈퍼를 통해 부류의 방법을 사용할 수 있는데, 어떻게 조부류의 방법을 사용할 수 있습니까?
  • package com.ljg;
    
    import android.os.Build;
    import android.support.annotation.RequiresApi;
    import java.lang.invoke.MethodHandle;
    import java.lang.invoke.MethodType;
    
    import static java.lang.invoke.MethodHandles.lookup;
    
    public class Test {
      class GrandFather {
        void say() {
          System.out.println("grandFather");
        }
      }
    
      class Father extends GrandFather {
        void say() {
          System.out.println("father");
        }
      }
    
      class Son extends Father {
        void say() {
          // 
          super.say();
          // 
          try {
            MethodType methodType = MethodType.methodType(void.class);
            MethodHandle methodHandle =
                lookup().findSpecial(GrandFather.class, "say", methodType, getClass());
            methodHandle.invoke(this);
          } catch (Throwable throwable) {
            throwable.printStackTrace();
          }
        }
      }
    }
    

    4. 창고 기반 명령 집합과 레지스터 기반 명령 집합


    주류 PC기의 지령집 구조는 [레지스터]에 의존하여 작업하는 것이다.
  • 1+1 창고 기반 지령집:iconst1 iconst_1 iadd istore_0[창고 꼭대기의 값을 국부 변수표의 0번째 Slot에 넣는다.]
  • 1+1 레지스터 기반 명령 집합: mov eax, 1 add eax, 1 [결과는 EAX 레지스터에 저장]
  • 창고 기반 지령집의 [장점]:1) 이식 가능.레지스터는 하드웨어가 직접 제공하는 것이고 창고 구조의 지령집을 사용하면 사용자 프로그램은 레지스터를 직접 사용하지 않는다. 가상 기기는 스스로 빈번하게 접근하는 데이터(예를 들어 프로그램 계수기, 창고 꼭대기 캐시)를 레지스터에 넣어 더욱 좋은 성능을 얻을 수 있다.2) 코드 컴파일러 구현 간단
  • 창고 기반 명령 집합의 [단점]: 실행 속도가 느립니다.원인: 1) 명령 수량은 일반적으로 레지스터 구조보다 많은데 출고 입고 조작으로 인해 많은 명령이 발생하기 때문이다.2) 스택의 현재 메모리에서 빈번한 스택 접근도 빈번한 메모리 접근을 의미한다.비록 가상 기기는 [창고 캐시] 수단을 사용하여 가장 자주 사용하는 조작을 레지스터에 비추어 메모리에 직접 접근하는 것을 피할 수 있지만 이것은 문제를 해결하는 본질이 아니라 최적화 조치일 뿐이다.따라서 명령 수량과 메모리 접근 때문에 창고 구조의 명령 집합의 실행 속도가 느리다.
  • 좋은 웹페이지 즐겨찾기