Javaコード実行プロセスの概要

5129 ワード

Javaコードには、ソース・コード・フェーズ(Source)->クラス・ロード・フェーズ(ClassLoader)->ランタイム・フェーズ(Runtime)の3つのフェーズがあります.
      
まず、Javaコードの実行プロセス全体を整理し、全体的な認識を持ってみましょう.
Javaソースプログラム(.java)はJavaコンパイラ(javac)を通過した後、1つ以上のバイトコード(.class)ファイルを生成し、JVMは実行するバイトコードをクラスローダClassLoaderを介してメモリにロードし、バイトコード検証器の検証を経て、Java解釈器は対応するマシンコードに翻訳し、 最後にオペレーティングシステムで実行を説明する.
 
プログラムがクラスを使用する場合、クラスがメモリにロードされていない場合、システムはロード、接続、初期化の3つのステップでクラスを初期化します.
ロードとは、classファイルをメモリに読み込み、クラスオブジェクトを作成することです(クラスが使用されるとシステムが作成し、クラスオブジェクトが1つしか作成されません).
JVMのクラス・ロード・フェーズでは、次の3つのことが必要です.   
    1. クラスの全限定名によって、このようなバイナリバイトストリームを定義します. 
    2. このバイトストリームが表す静的ストレージ構造をメソッド領域のランタイムデータ構造に変換する
    3. Javaスタックにこのクラスを表すjava.lang.Classオブジェクトを生成し、メソッド領域のこれらのデータへのアクセスエントリとして使用します.
クラスのロードされた最終製品はヒープ領域にあるClassオブジェクトであり、Classオブジェクトはメソッド領域内のクラスのデータ構造をカプセル化し、Javaプログラマにメソッド領域内のデータ構造にアクセスするインタフェースを提供する.
 
クラスのロードタイミング
    1. クラスのインスタンスの作成
    2. クラスの静的変数を使用するか、静的変数に値を割り当てます.
    3. 呼び出しクラスの静的メソッド
    4. クラスまたはインタフェースに対応するjava.lang.Classオブジェクトを強制的に作成するには、反射を使用します.
    5. クラスのサブクラスを初期化
    6. Javaコマンドを直接使用してプライマリクラスを実行
通俗的にはクラスを使うだけでクラスがロードされます
 
JVMは実行時に3つのクラスローダからなる初期ローダ階層を生成する
  • Bootstrap ClassLoaderルートローダ 

  •        C++で書く
            ブートクラスローダとも呼ばれ、javaコアクラスのロードを担当するローダは直接取得できません
            例えばSystem,Stringなど,JDKにおけるJREのlibディレクトリの下rt,jarファイルに
  • Extension ClassLoader拡張クラスローダ
  •         JREの拡張ディレクトリにおけるjarパッケージのロードjre/lib/extディレクトリにおけるjarパッケージまたは-Djava,ext,dirs指定ディレクトリにおけるjarパッケージをワークライブラリにパッケージする
  • System ClassLoaderシステムクラスローダ(自分が書いたクラスおよびサードパーティ製クラスライブラリ(インポートされたjarパッケージ)をロード)
  •         JVM起動時にjavaコマンドからのclassファイルをロードし、classpath環境変数で指定したjarパッケージとクラスパスをロードします.
     
     
    接続とは、クラスのバイナリデータをJREにマージすることです. 
    接続には、次の3つのステップがあります.
    検証#ケンショウ# Classファイルにロードされたデータの正確性を確認
  • ファイルフォーマット検査:バイトストリームがClassファイルフォーマットの仕様に合致し、現在のバージョンの仮想マシン処理
  • によって処理できるかどうかを検査する.
  • メタデータ検査:バイトコード記述の情報を意味分析し、その記述の内容がJava言語規範の要求
  • に合致することを保証する.
  • バイトコード検査:データストリームと制御ストリームの分析を通じて、プログラムの意味が合法的で論理に合致する
  • であることを確定する.
  • シンボル参照検査:シンボル参照検査は、クラス自体以外(定数プール内の各種シンボル参照)の情報に対する整合性検査
  • と見なすことができる.


    正しい内部構造(コンストラクタ、メソッド、変数、コードブロック)があり、他のクラスと調和しているかどうか
    の準備を このフェーズでは、クラス変数にメモリを正式に割り当て、クラス変数の初期値を設定します.
    これらの変数に使用されるメモリはメソッド領域に割り当てられます.この場合、メモリ割り当てはクラス変数のみを含み、インスタンス変数は含まれません(インスタンス変数はオブジェクトがインスタンス化されるとオブジェクトとともにJavaスタックに割り当てられます). 
    また、 ここで割り当てられる静的クラス変数は、Javaコードではなく、デフォルト値として定義されます.ここで設定された初期値は、通常、データ型デフォルトのゼロ値(0,0 L,null,falseなど)です.
    明示的に与えられた値は、 正しい割り当ては初期化フェーズで実行されます.
    解析クラスのバイナリデータのシンボル参照を直接参照に置き換える
    たとえばクラス内のメソッドの演算では,演算中のシンボルa=1がaを除いて直接1となり,多くのリソースを節約できる.
     
     
    初期化とはクラスの静的変数に対して、静的コードブロックに対して初期化操作を実行することである.
          クラス初期化フェーズはクラスロードプロセスの最後のステップであり、前のクラスロードプロセスでは、ロードフェーズユーザーアプリケーションがカスタムクラスローダで参加できるほか、残りの動作は完全に仮想マシンが主導し、制御され、初期化フェーズになってから、クラスで定義されたJavaプログラムコードの実行が本格的に開始されます. 
    クラスに初期化する静的変数は正しい初期値を与え、JVMはクラスの初期化を担当し、主にクラス変数を初期化し、Javaでクラス変数の初期値を設定するには2つの方式がある.
  • 静的変数(クラス変数)を宣言するときの初期値の指定 
  • 静的コードブロックを使用してクラス変数の初期値
  • を指定する.

            初期化手順:
                1. このクラスがまだロードされていない場合、プログラムは先にクラスをロードして接続します.
                2. クラスの直接親が初期化されていない場合は、直接親を初期化します.
                3. クラスに初期化文がある場合、システムはこれらの初期化文を順次実行します.
    JVMはスタックメモリにオブジェクトを作成し、クラスのメンバー変数はスタックメモリに入り、デフォルト値を付与する 
      
      
    最後に私たちがよく知っているRuntimeのランタイム段階です
    Person p = new Person();
    p,study();

    上記のコードを実行すると、スタックメモリにPersonクラスのオブジェクトが作成され、スタックメモリにPersonタイプの参照変数pが格納され、pはそのオブジェクトのアドレスが格納され、そのオブジェクトを指す.pを呼び出すstudyメソッドは、実際には、オブジェクトがPersonクラスのワードノードオブジェクトを介してメソッド領域Personバイトコードのstudyメソッドにアクセスする
     
     
    名詞の解釈 :
    Javaソース:Javaソースコード、java言語で作成されたプログラム
    Javaクラス・ローダ(Java Classloader):Javaランタイム環境(JRE)の一部であり、JavaクラスをJVMのメモリ領域に動的にロードする役割を果たす
    JRE:Java Runtime Environment、Java実行環境です.内部にはJava仮想マシンといくつかの標準クラスライブラリ(Jarパッケージ)が含まれています.
    JARパッケージ: Javaプラットフォームアプリケーションまたはライブラリを開発するために、多くのJavaクラスファイル、関連するメタデータ、およびリソース(テキスト、ピクチャなど)ファイルを1つのファイルに集約するために一般的に使用されます.
    JVM: すなわちJava Virtual Machine Javaバイトコード(Java bytecode)の仮想マシン
    クラス(Class): クラスは共通の属性と動作を持つオブジェクトの集合であり、クラスはオブジェクトの属性と方法を定義します.
    バイトコード: バイトコードは既にコンパイルされていますが、特定のマシンコードとは関係なく、解釈器が翻訳されてからマシンコードの中間コードになる必要があります.
    Javaバイトコード:Java仮想マシンが実行する命令フォーマット
    Javaコンパイラ:Javaソースファイル(.javaファイル)をバイトコードファイル(.classファイル、特殊なバイナリファイル、バイナリバイトコードファイル)にコンパイルします.このバイトコードはJVMの「マシン言語」で、javacコマンドはJavaコンパイラと簡単に見ることができます
    Java解釈器:JVMの一部であり、Java解釈器はJavaコンパイラのコンパイルを実行したプログラムを解釈するために使用され、javaコマンドは簡単にJava解釈器と見なすことができる
    ランタイムクラス: メモリにロードするバイトコードファイルに対応するクラスをランタイムクラスと呼び、 このランタイムクラスはクラスのインスタンスです
    Javaヒープ(Heap): JVMの起動時に作成されるのは、JVMが管理するメモリの中で最大のブロックです. JVMでは、ヒープ(Heap)は、各スレッドが共有できるランタイムメモリ領域であり、すべてのクラスインスタンスと配列オブジェクトにメモリを割り当てる領域でもあります. Javaスタックは、すべてのスレッドで共有されるメモリ領域です. Javaスタックはゴミ収集器管理の主なエリアです
    Javaスタック(Stack): 関数に定義された基本タイプの変数、Java命令コード、オブジェクトの参照変数は、関数のスタックメモリに割り当てられます.変数の役割ドメインを超えると、Javaはその変数に割り当てられたメモリ空間を自動的に解放します.
    メソッド領域(Non-Heap):  メソッド領域はJavaスタックと同様に、各スレッドが共有するメモリ領域であり、仮想マシンにロードされたクラス情報(構築方法とインタフェース定義)、定数、静的変数、インスタントコンパイラによってコンパイルされたコードなどのデータを格納するために用いられる. 実行時定数プールはメソッド領域に存在します