【java】JVM構造とクラスのロード原理


Java言語ではクラスはJVMにロードするのみ実行でき、指定javaプログラムを実行するとJVMはコンパイル生成する.classファイルは一定のルールでメモリにロードされ、完全なアプリケーションに整理されます.クラスのロードプロセスはクラスローダによって行われ(つまりClassLoaderとそのサブクラスによって行われる)、クラスローダ自体もクラスであり、本質的にはクラスファイルをハードディスクからメモリにロードする.
クラスのロード方法は2つあります.
(1)明示的なロード
classを呼び出す.forName()メソッドは、必要なクラスをJVMにロードします.
(2)暗黙的なロード
プログラムは新しいオブジェクトを作成する時、暗黙的にクラスローダを呼び出して対応するクラスをJVMにロードする
Java言語では、クラスのロードは動的で柔軟であり、大きなプロジェクトには多くのクラスが含まれ、各クラスまたはインタフェースは1つに対応することが多い.classファイル、プログラムが実行されると必要なクラスだけが必要になります(基本クラスなどのプログラム実行を保証するベースクラス)JVMにロードすると、一時的に不要なクラスは先にロードしなくてもよい.これにより、実行速度が向上する一方で、プログラム実行時のメモリのオーバーヘッドを低減することができる.また、各クラスファイルは動的なロードユニットと見なすことができ、プロジェクトがあるクラスを修正する必要がある場合、修正が完了した後はすべてのクラスを再コンパイルすることなく、変更されたクラスを再コンパイルしてロードする必要があります.
クラスは3つに分けることができます:システムクラス、拡張クラス、カスタムクラス、javaは異なるクラスによって異なるクラスローダを提供します
Bootstrap Loader<==ロードシステムクラス(jre/lib/rt.jarのクラス)
              �K
ExtClassLoader<==拡張クラス(jar/lib/etc/*.jarのクラス)をロード
                  �K
AppClassLoader<==アプリケーションクラスのロード(classpathで指定したディレクトリまたはjarのクラス)
具体的な手順:
(1)まずjava.exeはJREを見つけ、JREの内部にあるjvm.dllを見つけます.これが本当のjava仮想マシンです.その後、ダイナミックライブラリにロードし、java仮想マシンをアクティブにします.
(2)初期化操作を行い、終了後にBootstrap Loader起動クラスローダを生成する
(3)Bootstrap Loader基本的な初期化動作に加えて、最も重要なのはExtClassLoader拡張クラスローダをロードし、そのParentをnullと設定し、親ローダをBootstrap Loaderとする
(4)次いでBootstrap LoaderはLauncher.javaのAppClassLoader(カスタムクラスローダ)のロードを要求し、そのParentをExtClassLoaderエンティティとして設定し、この2つのローダはいずれも静的クラスとして存在する.
※注意が必要なのは、parentが誰なのかは誰にロードされたのかとは直接関係ありません
テストしてみましょう
package test;

public class classloader {
    public static void main(String[] args)
    throws Exception{
        ClassLoader App = classloader.class.getClassLoader();//class   
        System.out.println(App);
        ClassLoader Ext = App.getParent();//      
        System.out.println(Ext);
        ClassLoader Boot = Ext.getParent();//     
        System.out.println(Boot);
    }

}

実行結果:
[email protected]$ExtClassLoader@2490fd20null
Bootstrap Loader出力nullはC++言語で実現されているためjava言語では見られない
プログラムはclassloaderというクラスがAppClassLoaderによってロードされたことを説明します.
クラスのロードには主に3つのステップがあります.
(1)マウント:検索パスに基づいて適切なclassファイルを見つけてインポート
(2)リンク:classファイルが正しいかどうかを確認-->クラス内の静的変数に記憶領域を割り当てる-->シンボル参照を直接参照に変換
(3)初期化:静的変数と静的コードブロックの初期化操作
両親の委託メカニズム:
親委任モード、すなわち、クラス・ローダがタイプをロードするために別のクラス・ローダを要求するプロセスです.
クラス・ローダを起動する以外の各クラス・ローダには、特定のクラス・ローダが通常の方法でクラスをロードしようとする前に、デフォルトでこのタスクを親に「委任」し、親にクラスをロードするように要求する「親」クラス・ローダがあります.この両親は、このタイプをロードするために自分の両親に順番に要求します.この委任プロセスは、クラスローダが起動するまで継続し、通常、クラスローダが委任チェーンの最後のクラスローダである.クラス・ローダの親クラス・ローダがこのタイプをロードする能力がある場合.このクラス・ローダは、このタイプを返します.そうでなければ、このクラスローダは自分でこのクラスをロードしようとします.1つのプログラムが実行すると、仮想マシンは起動時に2つのユーザカスタムクラスローダをインスタンス化する:1つの「拡張クラスローダ」、1つの「カスタムクラスローダ」である.これらのクラス・ローダは、起動クラス・ローダとともにParent-Child委任チェーンに接続され、起動クラス・ローダは最上位にあります.
 
例:
package java.lang
public class String    //     JDK String    
{     
    public static void main(String[] args)
    {
    
    }
}

JDKのStringと同じクラスを定義しましたjava.langは同じですが、定義したStringクラスに主関数が含まれています.
実行結果:
java.lang.NoSuchMethodError: mainException in thread "main"
このような結果が得られたのは、
コードを実行すると、JVMはまずカスタムクラスローダーを作成します.AppClassLoaderと呼ばれ、このローダーを依頼チェーンにリンクします.AppClassLoader->ExtClassLoader->BootstrapLoaderです.AppClassLoaderはjavaをロードします.lang.StringのリクエストはExtClassLoaderに委任され、ExtClassLoaderは最後の起動クラスローダBootstrapLoaderに委任されます.クラスローダーBootstrapLoaderを起動するにはJAVAしかロードできません.HOMEjrelibのclassクラス(すなわちJ 2 SE API)は、標準APIにjavaがある.lang.Stringですが、このクラスは私たちが定義したクラスではありません.BootstrapLoaderはこのクラスを見つけたと思ってj 2 se apiのjavaをロードした.lang.String.
最後に上のロードエラーが発生しました.これは異常ではありません.JVMはAPIのStringクラスにmainメソッドがないため、終了しました.