1.仮想マシンスタックの構造
Java 仮想マシン スタックは、初期には Java スタックと呼ばれていました. スレッドが作成されるたびに、対応する仮想マシン スタックが作成されます. そのライフ サイクルは、スレッドのライフ サイクルと一致しています. 仮想マシン スタックはスタック フレームで構成され、各スタック フレームはメソッドに対応し、メソッド呼び出しはスタック フレームがスタックにプッシュされることに対応し、メソッドが終了してスタック フレームがスタックからポップされます。スタック内の各スタック フレームは、ローカル変数テーブル、オペランド スタック、ダイナミック リンク、メソッド リターン アドレス、および追加情報で構成されます。スタックの構造は次のとおりです。
2.仮想マシンスタックの特徴
-
仮想マシン スタックは、ストレージを割り当てるための高速かつ効果的な方法であり、そのアクセス速度はプログラム カウンターに次ぐものです。
-
仮想マシン スタックには、プッシュとポップの 2 つの操作しかありません。
メソッド呼び出しはスタックにプッシュされ、メソッドの実行が終了するとメソッドがポップアウトされます。
-
仮想マシン スタックにガベージ コレクションの問題はありません
-
仮想マシン スタックには、次の 2 つの例外がある場合があります: StackOverFlowError、OutOfMemoryError
仮想マシン スタックのサイズは、動的に設定することも、固定することもできます。スタック サイズが固定の場合、すべてのスタック フレーム サイズの合計がスタック サイズより大きい場合、またはスタック フレームがスタックより大きい場合、StackOverFlowError 例外が報告されます。スタック サイズが動的な場合、スタックは適用できません。より大きなスタック スペースの場合、またはメモリ サイズが新しいスタックを作成できない場合、OutOfMemoryError 例外が報告されます。
3. 仮想マシンスタックの動作原理
- アクティブなスレッドでは、一度にアクティブにできるスタック フレームは 1 つだけです。現在実行中のメソッドに対応するスタック フレームのみが有効です. 現在有効なスタック フレームは現在のスタック フレーム (スタック トップ スタック フレーム) になり、現在のスタック フレームと呼ばれ、対応するメソッドは現在のメソッドと呼ばれます.このメソッドは、現在のスタック フレームと呼ばれます。
- 現在のメソッドが他のメソッドを呼び出す場合、新しいスタック フレームが作成されてスタックにプッシュされ、新しい現在のスタック フレームになります。
- 実行エンジンによって実行されるバイトコード命令は、現在のスタック フレームのみを対象としています。
- 別のスレッドのスタック フレームを別のスレッドのスタック フレームで参照することはできません。
- このメソッドには 2 つの return メソッドがあります。1 つは通常に戻る方法で、もう 1 つは例外をスローする方法で、どちらもスタック フレームがスタックから飛び出します。
次のコードは、メソッドの呼び出しとスタック フレームのアクティビティを示しています。
/**
* @author cx
* @date 2022/10/24
*/
public class StackDemo01 {
public static void main(String[] args) {
System.out.println("main方法开始运行...");
method1("main");
System.out.println("main方法运行结束...");
}
static void method1(String name){
System.out.println("method1被" +name+ "方法调用了..." );
method2("method1");
System.out.println("method1运行结束...");
}
static void method2(String name){
System.out.println("method2被" +name+ "方法调用了..." );
method3("method2");
System.out.println("method2运行结束...");
}
static void method3(String name){
System.out.println("method3被" +name+ "方法调用了..." );
System.out.println("method3运行结束...");
}
// console:
// main方法开始运行...
// method1被main方法调用了...
// method2被method1方法调用了...
// method3被method2方法调用了...
// method3运行结束...
// method2运行结束...
// method1运行结束...
// main方法运行结束...
}