メインフレームの闇を照らす:STATIC変数とAUTOMATIC変数の「生存期間」を正しく理解する
現場の若手エンジニアから、たまにこんな質問を受ける。「なぜこの変数は、サブルーチンを抜けても値が残っているのか?」「なぜこのポインタは、次の呼び出しで予期せぬアドレスを指しているのか?」と。
大規模バッチの改修やマイグレーションの現場では、コンパイラの仕様を「なんとなく」で使っていると、必ずと言っていいほど不可解なバグに足元をすくわれる。今日は、PL/Iのメモリ管理の根幹である「生存期間(Storage Duration)」、特にSTATICとAUTOMATICの違いについて、現場の視点から深掘りしていこう。
—
1. 記憶域クラスの基本:STATIC vs AUTOMATIC
PL/Iにおいて、変数の宣言時に指定する記憶域クラスは、単なる「型」以上の意味を持つ。それは、その変数が「いつ生まれ、いつ消えるか」という寿命を決定する。
- AUTOMATIC(デフォルト): ブロック(PROCEDUREやBEGIN)に入った瞬間にメモリが確保され、ブロックを抜けると容赦なく破棄される。いわゆる「スタック」上のデータだ。
- STATIC: プログラムのロード時にメモリが確保され、プログラムの終了までその領域は固定される。まさに「基幹システムの番人」だ。
なぜこれが「バグの温床」になるのか?
現場でよく見る悲劇は、「再入可能(Reentrant)であるべきモジュールで、安易にSTATIC変数を使ってしまう」パターンだ。特に、CICSやマルチスレッド環境に近い制御フローを持つプログラムでこれをやると、前のトランザクションのゴミが次の処理に引き継がれ、原因不明の誤計算を引き起こす。
—
2. 実践的なコードで見るメモリ配置の挙動
以下のコードを見てほしい。VSAMファイルへのアクセスと、STATIC変数を活用した「呼び出し回数のカウント」を実装した例だ。
1
/ PROGRAM: SAMPLE01 – STATICとAUTOMATICの挙動デモ /
TEST_PROC: PROCEDURE OPTIONS(MAIN);
/ STATICはロード時に一度だけ初期化される /
DCL CALL_COUNT FIXED BIN(31) STATIC INIT(0);
/ AUTOMATICはPROCEDUREが呼ばれるたびに再構築される /
DCL WORK_AREA CHAR(80) AUTOMATIC;
/ 処理開始 /
CALL_COUNT = CALL_COUNT + 1;
PUT SKIP LIST(‘今回の呼び出し回数:’, CALL_COUNT);
/ 内部サブプロシージャ呼び出し /
CALL SUB_PROCESS;
/ 終了処理 /
RETURN;
SUB_PROCESS: PROCEDURE;
/ この変数はここを抜けると消滅する /
DCL LOCAL_BUFFER CHAR(10) AUTOMATIC INIT(‘DATA_VAL’);
PUT SKIP LIST(‘内部処理中:’, LOCAL_BUFFER);
END SUB_PROCESS;
END TEST_PROC;
ここが技術のポイント
- 初期化のタイミング: `STATIC`変数の`INIT`値は、プログラムがロードされた瞬間に一度だけ設定される。`CALL`されるたびに0に戻ることはない。
- スタック領域の節約: 大きな配列(`DCL BIG_ARRAY(10000) CHAR(100)`など)を`AUTOMATIC`で宣言すると、プログラム開始時にスタックが溢れる可能性がある。大規模データは`STATIC`、あるいは`CONTROLLED`(必要に応じて自分で確保・解放)を用いるのが賢い設計だ。
—
3. トラブルシューティングの現場から:ONユニットとの付き合い方
`ON`ユニット(例外処理)を書く際にも、この「寿命」は重要だ。`ON`ユニット内で`AUTOMATIC`変数を参照しようとすると、その変数が宣言されたブロックが既に終了していれば、参照先は不正なメモリ領域(ダングリング・ポインタに近い状態)になる。
1
/ ファイル読み込みの例外処理 /
ON ENDFILE(VSAM_FILE) BEGIN;
/ ここでAUTOMATIC変数を参照してはいけない! /
/ 既に制御が戻っている可能性があるため /
PUT SKIP LIST(‘ファイル終了しました’);
END;
もし、`ON`ユニットで状態を保持したい場合は、必ず`STATIC`、あるいは外部から渡された引数(ポインタ)を経由して安全を確保する必要がある。
—
4. ベテランからのアドバイス:保守性を高めるために
1. デフォルトを信じるな: `AUTOMATIC`が暗黙的であることは知っておくべきだが、コードレビューでは明示的に`DCL VAR AUTOMATIC`と書く文化があっても良い。意図が明確になるからだ。
2. デバッグのコツ: 「値がなぜか変わっている」という現象に遭遇したら、まずはその変数が`STATIC`かどうかを確認せよ。複数個所で更新されている可能性が極めて高い。
3. BUILTIN関数の活用: `ADDR(変数)`を使って、変数がスタック上にあるのか(アドレス値が特定範囲内)、それとも静的領域にあるのかをダンプ出力で追う技術は、メインフレームエンジニアの最後の砦だ。
PL/Iは古いが、そのメモリ管理モデルは極めて論理的だ。STATICとAUTOMATICの境界を意識することは、単にバグを防ぐだけでなく、コンピュータのメモリ構造を理解するということと同義である。
今日のコード改修も、この視点を持って臨んでみてほしい。きっと今まで見えなかった「メモリの息遣い」が聞こえてくるはずだ。
