JVM이 클래스 로더의 (A) 부분, 클래스 변수, 상수,의 깊이 이해 JVM 매개 변수

클래스 로딩 개요

  1. 자바 코드, 유형연결 부하 받는 초기화 과정은 프로그램 실행 중에 완료

    타입 : 클래스, 인터페이스 (객체 자체) 유형이 동적 프록시로서 동작 중에 생성 될 수있다. 한 종류 runting 개념

로드 : 이미 클래스의 바이트 코드 파일 (을 .class 파일)을 기존하는 가장 일반적인 방법입니다은 디스크에서 메모리로로드;

연결 : 클래스의 클래스 관계 셋다운 일부 처리 상관 바이트 코드 검증 연결 단계 완료

초기화 : 일부 정적 변수의 복사

이 과정은 사양에 따라,이 순서대로 필요는 없다

  1. 더 큰 유연성을 제공, 더 많은 가능성을 증가

    자체는 정적으로 입력 된 언어이지만 기능과 동적 인 특성의 많은 자바를 만든다

클래스 로더 심층 분석

  • 자바 가상 머신 및 애플리케이션 라이프 사이클 : 다음과 같은 경우, Java 가상 머신은 수명이 종료됩니다

    을 System.exit ()의 구현 방법

이 프로그램은 정상적으로 종료

중단 실행 동안 예외 또는 오류가 발생

운영 체제 오류는 Java 가상 머신을 종료하는 과정을 발생하기 때문에

클래스로드가 연결이 초기화가 더 설명

  • 로드 : 이진 데이터의 클래스를 찾아로드

    클래스 파일 (파일이 반드시 등, 네트워크 데이터베이스의 소스하지 않을 수 있습니다) 메모리에로드

  • 연결
    • 확인 : 확인 클래스가로드되어 있는지 확인 정확성을
    • 제조 : 클래스의 정적 변수 메모리를 할당하고 초기화 기본값 .

      Object 클래스의 인스턴스에서 생성되지 않았습니다

//假设代码中有
class Test{
    public static int a = 1; 
}
//在准备这个阶段,虚拟机在准备阶段不会将1赋值给a,它会为a分配内存并且把0赋值给a
    • 분석 : 클래스를 직접 참조 기호 참조로 변환

      상징적 참조 : 간접 참조

직접 인용 : 직접 객체 참조 점 위치 메모리

  • 초기화 : 클래스에 대한 정적 변수 의 올바른 초기 값을 부여
//假设代码中有
class Test{
    public static int a = 1; 
}
//在准备阶段,虚拟机在准备阶段不会将1赋值给a,它会为a分配内存并且把0赋值给a
//在初始化阶段,将a=0替换为a=1

제거 클래스를 사용하여

  • 클래스의 사용

    객체를 생성, 사용

  • 클래스 하역

    > 메모리에서 파괴, OSGI

    클래스 로더

    능동 및 수동 사용을 사용하여

    모든 자바 가상 머신의 구현은 "각 클래스 또는 인터페이스에서 자바 프로그램을해야합니다 첫 번째 활성 사용 "그들은 때를 초기화

  • 자바 프로그램 수준의 사용은 두 가지로 나누어진다
  1. 활성 사용 (칠가지)
  • 클래스의 인스턴스를 생성

  • 클래스 또는 인터페이스 또는 정적 변수 할당의 액세스 정적 변수 (니모닉 : getstatic, putstatic)

  • 정적 클래스 메소드 호출 (니모닉 : invokestatic (이))

  • 반사경 (예를 Calss.forName ( "com.test.Test"))
  • 클래스의 서브 클래스를 초기화

    클래스가 부모 클래스를 초기화하는 부모 클래스가있는 경우, 부모 클래스는 부모 클래스가있는 경우,이 초기화까지 될 것입니다, 클래스를 초기화

  • 자바 클래스가 시작 클래스로 표시되어 가상 머신 (자바 테스트)

  • 동적 언어 지원 JDK1.7의를 제공하기 시작

    분석 결과 REF_getStatic java.lang.invoke.MethodHandle, REF_putStatic의 예로는, 대응하는 핸들 REF_invokeStatic 클래스 초기화 초기화되지

  1. 수동 사용
  • 위의 경우 중 하나에 추가하여, 자바 클래스를 사용하는 다른 방법의 일종으로 볼 수 있습니다 수동 사용하는 클래스가 발생하지 않습니다, 초기화를

    클래스를로드 할 수 수동 사용 만하지 말고 초기화

클래스 로딩

  • 클래스 로딩

    로드 이진 데이터 판독 메모리 영역에있어서 배치 런타임 데이터 영역으로의 .class 파일 클래스의 클래스를 의미하고 지정하지 않는 (메모리에의 java.lang.Class 객체를 만들 물체가있는 클래스의 설명은 핫스팟 가상 머신은 면적 법)에 프로세스 영역에서 클래스의 데이터 구조를 패키징하는데 사용된다

로드을 .class는 방법을 파일

  1. 로컬 파일 시스템에 직접로드에서 (가장 일반적인)
  2. 네트워크를 통해 다운로드 class 파일
  3. 우편, 항아리와 아카이브의 다른 종류의 가격을 물어에서 .Calss로드 파일
  4. 독점 데이터베이스에서 파일의 압축을 풉니 다 .Calss
  5. 자바 소스 파일을 동적으로 .calss 파일로 컴파일 (런타임을 만들 동적 프록시, 웹 개발자가 사용됩니다)

예를 들면

eg1:
public class MyTest {

    public static void main(String[] args) {
        System.out.println(MyChild1.str1);
    }

}

class MyParent1 {
    public static String str1 = "hello world str1";
    static {
        System.out.println("MyParent1 static block");
    }
}

class MyChild1 extends MyParent1 {
    public static String str2 = "hello world str2";
    static {
        System.out.println("MyChiled1 static block");
    }
}

//输出结果:
MyParent1 static block
hello world str1

들어 정적 필드직접 필드의 클래스가 초기화됩니다 정의합니다 . 따라서, 본 실시 예에서, MyParent1 STR1의 직접적인 사용은, 그것을, MyChild1를 초기화 할 것이다 MyParent1 초기화한다 MyParent1 적극 사용을 위해 .

"각 클래스 또는 인터페이스에서 자바 프로그램을해야합니다 위의 자바 가상 머신의 구현의 모든 준수 첫 번째 활성 사용하기 가 초기화 할 때"

 eg2:
public class MyTest {

    public static void main(String[] args) {
        System.out.println(MyChild1.str2);
    }

}

class MyParent1 {
    public static String str1 = "hello world str1";
    static {
        System.out.println("MyParent1 static block");
    }
}

class MyChild1 extends MyParent1 {
    public static String str2 = "hello world str2";
    static {
        System.out.println("MyChiled1 static block");
    }
}
//输出结果:
MyParent1 static block
MyChiled1 static block
hello world str2

서브 클래스 초기화는 모든 부모 클래스 초기화 요구하고있다 본 실시 예에서, MyChild1의 STR2의 직접적인 사용은 그것이 초기화 MyChild1 것이다하지만 활성의 사용에 의해 서브 클래스가 초기화 를 들어, 볼 수있는 부모 클래스가 초기화됩니다. (각 클래스는 한 번만 초기화됩니다)

따라서, 본 실시 예에서는 그 출력 동작을 수행 MyChild1.str2 초기화 MyParent1 MyChild1 초기화 될

eg3:
//执行主类的 VM arguments 中 添加 -XX:+TraceClassLoading 
//打印类加载信息
public class MyTest {

    public static void main(String[] args) {
        System.out.println(MyChild1.str1);
    }

}

class MyParent1 {
    public static String str1 = "hello world str1";
    static {
        System.out.println("MyParent1 static block");
    }
}

class MyChild1 extends MyParent1 {
    public static String str2 = "hello world str2";
    static {
        System.out.println("MyChiled1 static block");
    }
}
//输出结果
[Loaded java.lang.Object from shared objects file]
[Loaded java.io.Serializable from shared objects file]
...
[Loaded java.security.UnresolvedPermission from shared objects file]
[Loaded java.security.BasicPermissionCollection from shared objects file]
[Loaded cn.lillcol.classloader.MyTest from file:/E:/lteworkspace/gaSvr/target/classes/]
[Loaded sun.launcher.LauncherHelper$FXHelper from shared objects file]
[Loaded java.lang.Class$MethodArray from shared objects file]
[Loaded java.lang.Void from shared objects file]
[Loaded cn.lillcol.classloader.MyParent1 from file:/E:/lteworkspace/gaSvr/target/classes/]
[Loaded cn.lillcol.classloader.MyChild1 from file:/E:/lteworkspace/gaSvr/target/classes/]
MyParent1 static block
hello world str1
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]

첫 번째 클래스는 java.lang.Object 상위를로드, 모든 클래스의 부모

MyChild1가 초기화되지 만, 가상 머신은 여전히 ​​MyChild1로드 있지만

그리고 우리는 관련 클래스로드 순서 MYTEST, MyParent1, MyChild1, 쓰기 Java 가상 머신 클래스에 MYTEST 클래스의 시작이 시작 클래스로 표시되는 것을 특징을

eg4:
public class MyTest {
    static {
        System.out.println("MyTest static block");
    }

    public static void main(String[] args) {
        System.out.println(MyChild1.str1);
    }

}

class MyParent1 {
    public static String str1 = "hello world str1";
    static {
        System.out.println("MyParent1 static block");
    }
}

class MyChild1 extends MyParent1 {
    public static String str2 = "hello world str2";
    static {
        System.out.println("MyChiled1 static block");
    }
}
//输出结果:
[Loaded cn.lillcol.classloader.MyTest from file:/E:/lteworkspace/gaSvr/target/classes/]
[Loaded sun.launcher.LauncherHelper$FXHelper from shared objects file]
[Loaded java.lang.Class$MethodArray from shared objects file]
[Loaded java.lang.Void from shared objects file]
MyTest static block
[Loaded cn.lillcol.classloader.MyParent1 from file:/E:/lteworkspace/gaSvr/target/classes/]
[Loaded cn.lillcol.classloader.MyChild1 from file:/E:/lteworkspace/gaSvr/target/classes/]
MyParent1 static block
hello world str1
[Loaded java.lang.Shutdown from shared objects file]
[Loaded java.lang.Shutdown$Lock from shared objects file]

MyParent1, MyChild1 전에 MYTEST로드 순서 는 Java 가상 머신의 클래스가 시작 클래스로 표시됩니다 시작

eg5:
public class MyTest2 {

    public static void main(String[] args) {

        System.out.println(MyParent2.str2);
    }

}

class MyParent2 {
    public static final String str2 = "hello world";
    static {
        System.out.println("MyParent2 static block");
    }
}
//输出结果
hello world

상수 컴파일 시간이 적립됩니다 이 상수 메서드를 호출 할 경우 클래스정수 풀 이다.

본질적으로, 클래스는 직접 클래스의 상수의 정의를 참조하지 않고 호출, 따라서 상수를 정의 클래스 실행되지 않습니다초기화를

참고 :이은을 말한다 일정과 str2 에 저장 MyTest2 정수 풀 MyTest2 및 MyParent2 어떤 관계가 아닌 한 후, 심지어 MyParent2의 .class 파일 삭제의이 시점에서 중요하지 않습니다

eg6:
public class MyTest3 {
    public static void main(String[] args) {
        System.out.println(MyParent3.str3);
    }
}
class MyParent3{
    public static final String str3= UUID.randomUUID().toString();
    static {
        System.out.println("MyParent3 static block ");
    }
}
//输出结果:
MyParent3 static block 
62322324-7b63-49c8-a8c4-f6607421f7ff

당신이 상수 값이 컴파일시에 결정할 수없는 경우, 그 값은 상수 풀에 클래스를 호출 할 것이다

프로그램을 실행할 때이 때, 주도권은 분명히이 클래스가 초기화에 리드 곳이 클래스 상수의 사용으로 이어질 것입니다

eg7:在终端下用 javap -c 命令反编译MyTest2的.calss文件
javap -c MyTest2

#输出结果
Compiled from "MyTest2.java"
public class cn.lillcol.classloader.MyTest2 {
  public cn.lillcol.classloader.MyTest2();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #22                 // String hello world
       5: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

니모닉 : LDC 스택으로 푸시하거나 상수 풀로부터 입력 문자열 상수 값의 INT 플로트를 도시

eg8:将代码作如下修改
public class MyTest2 {

    public static void main(String[] args) {

        System.out.println(MyParent2.s);
    }

}

class MyParent2 {
    public static final String str2 = "hello world";
    public static final short s = 7;
    static {
        System.out.println("MyParent2 static block");
    }
}
//输出:
7

//反编译结果:
Compiled from "MyTest2.java"
public class cn.lillcol.classloader.MyTest2 {
  public cn.lillcol.classloader.MyTest2();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: bipush        7
       5: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
       8: return
}

니모닉 : bipush 스택으로 푸시 된 상수 풀의 단일 바이트 (-128--127) 상수 값을 나타낸다

 eg9:将代码作如下修改
public class MyTest2 {

    public static void main(String[] args) {

        System.out.println(MyParent2.i);
    }

}

class MyParent2 {
    public static final String str2 = "hello world";
    public static final short s = 7;
    public static final int i = 128;
    static {
        System.out.println("MyParent2 static block");
    }
}
//输出:
128
//反编译结果:
Compiled from "MyTest2.java"
public class cn.lillcol.classloader.MyTest2 {
  public cn.lillcol.classloader.MyTest2();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: sipush        128
       6: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
       9: return
}

니모닉 : sipush 스택으로 푸시 된 상수 풀의 단일 바이트 (-32768--32767) 상수 값을 나타낸다

eg10:将代码作如下修改
public class MyTest2 {

    public static void main(String[] args) {

        System.out.println(MyParent2.m);
    }

}

class MyParent2 {
    public static final String str2 = "hello world";
    public static final short s = 7;
    public static final int i = 128;
    public static final int m = 0;
    static {
        System.out.println("MyParent2 static block");
    }
}
//输出:
0
//反编译结果:
Compiled from "MyTest2.java"
public class cn.lillcol.classloader.MyTest2 {
  public cn.lillcol.classloader.MyTest2();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: iconst_0
       4: invokevirtual #22                 // Method java/io/PrintStream.println:(I)V
       7: return
}

니모닉 : iconst_0 1 INT 상수 풀의 일종 스택에서 푸시 쇼 (iconst_m1 - iconst_5)

위치 저장 니모닉 다음의 rt.jar에서 JDK

eg11:
public class MyTest4 {
    public static void main(String[] args) {
        MyParent4[] myTest4s = new MyParent4[1];
        System.out.println(myTest4s.getClass());

        MyParent4[][] myTest4s1 = new MyParent4[1][1];
        System.out.println(myTest4s1.getClass());

        System.out.println(myTest4s.getClass().getSuperclass());
        System.out.println(myTest4s1.getClass().getSuperclass());
        
        int[] ints=new int[1];
        System.out.println(ints.getClass());
        System.out.println(ints.getClass().getSuperclass());
    }
}
class MyParent4{
    static {
        System.out.println("MyParent4 static block");
    }
}
//输出:
class [Lcom.aaa.test.MyParent4;
class [[Lcom.aaa.test.MyParent4;
class java.lang.Object
class java.lang.Object
class [I
class java.lang.Object

예를 들어 어레이, 그 형태가 동적 동작 동안 JVM에 의해 생성 된 클래스 [Lcom.aaa.test.MyParent4 표현 이러한 형태로 동적으로 생성 된 상위 클래스의 타입은 java.lang.Object 상위하다.

어레이 들어 javadoc 종종 어레이 요소가 감소 된 치수의 어레이를 입력 한 후에, 실제로 부품을 구성하는 것으로 함.

eg12:
        int[] ints=new int[1];
        System.out.println(ints.getClass());

        short[] showts=new short[1];
        System.out.println(showts.getClass());

        boolean[] booleans=new boolean[1];
        System.out.println(booleans.getClass());

        char[] chars=new char[1];
        System.out.println(chars.getClass());

        byte[] bytes=new byte[1];
        System.out.println(bytes.getClass());

        float[] floats=new float[1];
        System.out.println(floats.getClass());

        double[] doubles=new double[1];
        System.out.println(doubles.getClass());
//输出:
class [I
class [S
class [Z
class [C
class [B
class [F
class [D

니모닉 :

anewarray, 기준 (예를 들면 클래스, 인터페이스, 배열 등) 형 배열 및 스택으로 기준값을 생성 수단

ewarray : 생성 프리미티브 스택으로 지정된 형식의 배열 (예를 들어, INT, 부동 소수점, 문자 등)을, 참조 값을 나타낸다

JVM 인수

-XX:+<option>,表示开启option选项
-XX:-<option>,表示关闭option选项
-XX:<option>=<value>,表示将option选项的值设置value

+, - 때문에 기본적으로 설정 또는 해제 일부 매개 변수

이해와 경험이 JVM을주의 깊이있는이 문서 장 긴 학습 교사, 소스를 표시하시기 바랍니다! ! !

추천

출처www.cnblogs.com/lillcol/p/11129928.html