現場のエンジニアへ告ぐ:PL/Iのメモリ管理、AUTOMATICとSTATICを混同してはいけない理由
大規模なメインフレームの保守現場において、時折耳にする「なぜかバッチ実行中に変数の値がおかしくなる」という怪奇現象。その多くは、コンパイラがよしなにやってくれているメモリ管理の深淵、すなわち`AUTOMATIC`と`STATIC`の生存期間(Storage Duration)に対する理解不足に起因している。
今日は、PL/Iの基本構造である`PROCEDURE`と、その中で生きる変数たちがどのような「運命」を辿るのか、現場のリアルな視点から紐解いていこう。
—
1. AUTOMATICとSTATICの「生存期間」という名の格差
PL/Iにおいて、変数の属性を明示しない場合、デフォルトで`AUTOMATIC`が適用される。これは、その`PROCEDURE`が呼び出されるたびにスタック領域に領域が確保され、`END`で戻る際に消滅する「使い捨て」の変数だ。
対して`STATIC`は、プログラムがロードされた瞬間から終了まで、静的領域(ロードモジュールの一部)に鎮座し続ける「永住者」である。
なぜこれがトラブルの種になるのか?
実務でよくあるミスは、再帰呼び出し(Recursive Call)を行うプログラムで`STATIC`を安易に使ってしまうことだ。`STATIC`は全世代で単一のメモリを共有する。再帰の深さに関わらず、全ての呼び出しで同じメモリを参照するため、意図しない値の書き換えが起きる。
一方、`AUTOMATIC`であれば、呼び出しごとにスタック上の独立した領域に展開されるため、再帰構造においても安全だ。
—
2. 実践的なコードで見る生存期間の挙動
以下のコードを見てほしい。`AUTOMATIC`と`STATIC`の挙動の違いを可視化したものだ。
1
TEST_MEM: PROC OPTIONS(MAIN);
/ —————————————————– /
/ AUTOMATIC: 呼び出されるたびに初期化され、リセットされる /
/ STATIC: 一度値を保持すれば、次回の呼び出しまで維持される /
/ —————————————————– /
DCL AUTO_VAR FIXED BIN(31) AUTOMATIC INIT(0);
DCL STAT_VAR FIXED BIN(31) STATIC INIT(0);
/ サブルーチンを2回呼び出す /
CALL DEMO_PROC;
CALL DEMO_PROC;
DEMO_PROC: PROC;
AUTO_VAR = AUTO_VAR + 1;
STAT_VAR = STAT_VAR + 1;
PUT SKIP LIST(‘AUTO_VAR:’, AUTO_VAR); / 毎回 1 と表示される /
PUT SKIP LIST(‘STAT_VAR:’, STAT_VAR); / 1, 2, 3… と増加する /
END DEMO_PROC;
END TEST_MEM;
このコードを実行すると、`STAT_VAR`が前回の値を保持し続けていることに気づくだろう。もし、このプログラムが大量のVSAMレコードを処理するバッチの一部であり、`STAT_VAR`で合計値を算出している場合、リスタートや複数回呼び出しのロジックで致命的な計算ミスを引き起こす可能性がある。
—
3. 現場で役立つ「再帰」と「ONユニット」の注意点
大規模バッチの改修において、`ON ENDFILE`や`ON ERROR`といった`ONユニット`を使う場面は多い。ここで注意すべきは、`ONユニット`は`PROCEDURE`の終了後も有効な場合があるということだ。
特に、`AUTOMATIC`変数を`ONユニット`内で参照している場合、その`PROCEDURE`が既に`END`してメモリが解放されていると、期待した値にアクセスできない(あるいはABENDする)可能性がある。
- 鉄則1: `ONユニット`内で値の永続性が必要なら、`STATIC`変数、あるいは呼び出し元の親ブロックで確保された変数を使用すること。
- 鉄則2: 再帰呼び出しを行う場合は、ローカル変数には必ず`AUTOMATIC`(デフォルト)を明示し、不用意に`STATIC`を混入させないこと。
—
4. 最後に:ベテランからのアドバイス
「とりあえず`STATIC`にしておけば値が消えないから安心」という考えは、メインフレームの限られたメモリリソースを浪費するだけでなく、プログラムの可読性と保守性を著しく下げる。
特に、現代のマイグレーションプロジェクトにおいて、過去のスパゲッティコードを紐解く際、`STATIC`変数がプログラムのどの地点で書き換わっているかを追跡するのは至難の業だ。
- 基本はAUTOMATIC。
- 定数や、どうしてもプログラム全体で共有すべきカウンタのみSTATIC。
この原則を守るだけで、君たちが書くPL/Iコードの信頼性は劇的に向上する。デバッグに追われる時間を減らし、設計という本来のエンジニアリングに時間を使えるよう、日々のコーディング規約を大切にしてほしい。
何か不明点があれば、いつでもコンパイラのリスティングを片手に議論しよう。現場からは以上だ。
