Java実行環境における変数のライフサイクルは、宣言位置とメモリ領域の関係性によって厳密に制御されます。主要な変数タイプとその特性をメモリ管理の観点から解説します。
メモリ領域の基本構造
JVMは実行時に以下のメモリ領域を管理します:- スタック領域:メソッド実行時のコンテキスト管理
- ヒープ領域:オブジェクトインスタンスの格納
- メタスペース:クラスメタデータと静的メンバーの保持(JDK8以降)
変数タイプ別の動作特性
1. スタック変数(メソッド内宣言)
メソッド内部で宣言される変数はスタックフレームに格納されます:
- 有効範囲:宣言されたコードブロック内に限定
- 初期化:必須(未初期化アクセスはコンパイルエラー)
- ライフサイクル:メソッド実行終了と同時に解放
public void process() {
final int storageLevel = 3; // スタックに配置
String[] buffer = new String[10]; // 参照はスタック、実体はヒープ
}
2. インスタンス変数(オブジェクトメンバー)
クラス定義内に宣言され、オブジェクトごとに独立して保持されます:
- 有効範囲:クラス全メソッドからアクセス可能
- 初期化:省略可(数値型は0、参照型はnull)
- メモリ:ヒープ領域のオブジェクト領域に配置
public class DataContainer {
private double capacity; // ヒープに配置されるインスタンスメンバー
protected boolean isActive;
}
3. クラス変数(static修飾子付き)
全インスタンス間で共有される静的メンバー:
- 有効範囲:クラス名またはインスタンス経由でアクセス可能
- 初期化:クラスロード時に1度実行
- メモリ:メタスペース領域に格納(JDK8以降)
public class SystemConfig {
private static int maxThreads = 200; // メタスペースに配置
public static final String ENV = "production";
}
メモリ管理の実践的考察
| 変数タイプ | メモリ領域 | 解放タイミング | 初期値保証 |
|---|---|---|---|
| スタック変数 | スタック | メソッド終了時 | なし |
| インスタンス変数 | ヒープ | ガベージコレクション時 | あり |
| クラス変数 | メタスペース | アプリケーション終了時 | あり |
重要な実装上の注意点:
- 参照型のスタック変数はヒープオブジェクトへのポインタを保持
- 静的コレクションの不適切な使用はメモリリークを引き起こす
- プリミティブ型は直接値を保持、参照型は間接アクセス
実行フローの具体例
public class MemoryDemo {
private int instanceValue = 50;
private static int classValue = 100;
public void execute() {
int stackValue = 150;
System.out.println(stackValue);
}
public static void main(String[] args) {
MemoryDemo demo = new MemoryDemo();
demo.execute();
System.out.println(classValue);
}
}
実行時メモリ構造:
- mainメソッド実行でスタックフレーム生成
- demo参照がスタックに、オブジェクト実体がヒープに配置
- classValueはメタスペースに常駐
- execute呼び出しで新しいスタックフレームが作成