【PL/I深層】CONTROLLED属性によるスタック管理:メモリを支配し、再帰の罠を回避する
諸君、お疲れ様。今日もバッチ処理のABENDログと格闘しているか?
最近の若手は、JavaやPythonのようなガベージコレクションが効く言語に慣れすぎて、メモリ管理という概念を「ブラックボックス」だと思い込んでいる節があるな。だが、我々が扱うメインフレームの世界、特にPL/Iにおいては、メモリは「確保」し、「制御」し、そして確実に「解放」するものだ。
今日は、PL/Iのメモリ管理の華とも言えるCONTROLLED属性について語ろう。特に再帰呼び出し(Recursive Call)が絡むバッチ処理で、この属性を使いこなせるかどうかで、システムの堅牢性は天と地ほどの差が出る。
—
1. CONTROLLED属性とは何か
通常、PL/Iで宣言される変数は、`STATIC`(プログラム実行中ずっと生存)か`AUTOMATIC`(プロシージャ呼び出し時にスタックに積まれ、終了時に消える)だ。
しかし、`CONTROLLED`属性を付与した変数は、コンパイラ任せのスタック管理を許さない。「俺が、今、この瞬間に必要なメモリ量を知っている」というエンジニアが、ALLOCATE文とFREE文で、自らの手でスタックを構築するためのものだ。
基本構造と挙動
`CONTROLLED`変数は、実質的に「スタック(LIFO: Last-In, First-Out)」を形成する。
- `ALLOCATE`が呼ばれると、新しい世代がスタックの先頭に積まれる。
- `FREE`が呼ばれると、最新の世代が破棄され、一つ前の世代が再び有効になる。
これがなぜ重要か? それは、動的なデータ量変動と再帰呼び出し時のローカル領域の保護において、最強の武器になるからだ。
—
2. 実践:再帰処理とスタック管理
例えば、階層構造を持つVSAMデータの読み込みなどで、深さが未知の再帰処理を書く際、`AUTOMATIC`変数だけで凌ごうとするとスタックオーバーフローのリスクがある。ここで`CONTROLLED`の出番だ。
1
/ 再帰による階層データ処理のサンプル /
TEST_PROG: PROC OPTIONS(MAIN);
/ CONTROLLED変数の定義:スタックとして機能する /
DCL WORK_AREA CHAR(1024) CONTROLLED;
DCL LEVEL FIXED BIN(15) INIT(0);
/ 再帰呼び出しの実行 /
CALL PROCESS_NODE(1);
PROCESS_NODE: PROC(P_LEVEL);
DCL P_LEVEL FIXED BIN(15);
/ メモリの確保(スタックへのプッシュ) /
ALLOCATE WORK_AREA;
/ ここでVSAMからの読み込みや処理を行う /
/ WORK_AREAは、各階層ごとに独立した領域を持つ /
IF P_LEVEL < 10 THEN DO; CALL PROCESS_NODE(P_LEVEL + 1); END; / メモリの解放(スタックからのポップ) / FREE WORK_AREA; END PROCESS_NODE; END TEST_PROG; ---
3. なぜ「FREE」を忘れると悲劇が起きるのか
現場でよく見るバグが「`ALLOCATE`したままのメモリリーク」だ。特に`ON`ユニット(例外処理)内で処理を中断する場合、注意が必要だ。
もし`ON ERROR`や`ON ENDFILE`のブロック内で`GOTO`を使って処理を強引にスキップすると、`FREE`が実行されず、スタックが肥大化し続ける。そして最終的には`STORAGE CONDITION`が発生し、バッチは沈黙する。
プロの教訓:
`ON`ユニットを組むときは、必ず「正常終了ルート」と「異常終了ルート」のどちらを通っても、必要な`FREE`が実行されるような構造(あるいは、スタックをクリアするクリーンアップルーチン)を設計しろ。
—
4. 保守・移行現場でのデバッグのコツ
既存のレガシーコードを解読する際、`CONTROLLED`変数の世代数を確認したくなることがあるはずだ。そんな時は、メインフレームのデバッグツール(IBM z/OS Debuggerなど)で、`ALLOCATION`状態をウォッチする癖をつけておけ。
また、`BUILTIN`関数の活用も忘れるな。
- `ALLOCATION(変数名)`:その変数が現在スタックにいくつ積まれているか(世代数)を返す。
- この値をログに出力するだけで、無限ループやスタック溢れの予兆を検知できる。
1
/ 世代数チェックの例 /
IF ALLOCATION(WORK_AREA) > 100 THEN DO;
PUT SKIP LIST(‘WARNING: WORK_AREA STACK IS TOO DEEP!’);
/ 適切な異常終了処理へ /
END;
—
最後に:アーキテクトからの助言
`CONTROLLED`属性は「諸刃の剣」だ。しかし、これがあるからこそ、我々は制約の厳しいメインフレーム上で、動的なメモリ制御という高度な芸当が可能になる。
JavaやC#に浮気したくなる気持ちはわかる。だが、メモリの端から端までを自分のコードで支配するこの感覚こそ、メインフレームエンジニアの真骨頂だ。
次にコードを書くとき、`ALLOCATE`という命令を打つその指先に、メモリの状態をイメージしてくれ。それができれば、君も一人前のPL/I使いだ。
何か詰まったら、いつでも聞いてくれ。現場からは以上だ。
