【実務・中級編】AUTOMATIC変数の初期値設定とINITIAL属性 – PL/Iの基本構文とデータ制御実践ガイド

「INITIAL属性」のコストと自動変数の罠:メインフレーム・プログラミングの深淵

夜中のバッチ処理で、なぜか特定の日だけCPU時間が跳ね上がる――。そんな不可解な事象に直面したとき、多くのエンジニアが真っ先に疑うのはJCLのパラメータやVSAMのバッファ設定だろう。だが、PL/Iの老練なアーキテクトから見れば、犯人は往々にして「何気なく書いた`INITIAL`属性」にある。

今日は、若手エンジニアが陥りやすい`AUTOMATIC`変数の罠と、その裏側にあるコンパイラの挙動について、現場の知見を交えて紐解いていこう。

1. AUTOMATIC変数とINITIALの「見えない再計算」

PL/Iの`AUTOMATIC`変数は、その`PROCEDURE`が呼び出されるたびにスタック上に確保され、終了とともに解放される。ここまでは教科書通りだ。しかし、そこに`INITIAL`属性を付与した瞬間、コンパイラは「呼び出しのたびにその値を代入する」という命令を生成する。

もし、数百万回ループするサブルーチンの中で大きな構造体や配列を`INITIAL`で初期化していればどうなるか。当然、CPUは「毎回」その代入処理を黙々と実行する。これが大規模バッチにおける隠れたボトルネックの正体だ。

実践的なコード例:改善の指針

以下のコードを見てほしい。頻繁に呼び出されるサブルーチン内での効率的な初期化の書き方だ。

1
//
/ サブルーチン呼び出し時の初期化オーバーヘッドを抑制する工夫 /
//
MY_SUB: PROC(P_INPUT);
DCL P_INPUT CHAR(10);

/ 悪い例:呼び出しごとに再初期化が発生する /
/ DCL WORK_BUF(1000) CHAR(80) INITIAL(‘ ‘); /

/ 推奨例:STATIC属性とブランク代入の使い分け /
/ 初回のみ初期化したい場合はSTATICを使う /
DCL STATIC_BUF(1000) CHAR(80) STATIC INITIAL(‘ ‘);

/ 毎回クリアが必要なら、BUILDIN関数を活用して高速化する /
DCL WORK_BUF(1000) CHAR(80) AUTOMATIC;

/ STRZAIやASSIGN系でクリアする方が、コンパイラが最適化しやすい /
/ 構造体全体をまとめてクリアするならASSIGNまたは組み込み関数 /
WORK_BUF = ‘ ‘;

/ VSAMアクセス等でONユニットを定義する場合のフロー /
ON ENDFILE(VSAM_FILE) BEGIN;
PUT SKIP LIST(‘EOF REACHED’);
/ ここでの制御フローには注意が必要 /
END;

/ 実務上のヒント:ONユニットは必要最小限のスコープで定義すること /
END MY_SUB;

2. コンパイラの最適化と「静的(STATIC)」という選択肢

「毎回同じ値で初期化するなら、なぜ`STATIC`を使わないのか?」――そう問いたい場面は多い。`STATIC`属性を付与すれば、その変数はロードモジュール内にデータとして配置される。つまり、プログラムの実行開始時に一度だけメモリにロードされ、その後は値が保持される。

ただし、注意が必要だ。`STATIC`変数は、マルチスレッド環境(CICSのタスク共用や、再入可能コード)では予期せぬ副作用を生む。「前回処理のゴミが残っている」というバグは、メインフレーム開発において最も見つけにくい類のものだ。

現場で役立つデバッグのコツ

  • 再入可能性(REENTRANT)の維持: プログラムが`REENTRANT`属性でコンパイルされているなら、`STATIC`の使用は慎重に。
  • ONユニットの罠: `ON`ユニット内で`AUTOMATIC`変数を参照する場合、その変数が「どの呼び出しレベル(Invocation Level)のものか」を常に意識すること。`ON`ユニットはスタックフレームをまたいで発火するため、意図しないスコープの変数を書き換えてしまう事故が後を絶たない。

3. なぜ「今」この知識が必要なのか

現在、多くの企業がメインフレームのマイグレーションや、レガシーコードのオープン系移行を検討している。しかし、その過程で「なぜこの古いコードはこんな書き方をしているのか?」という疑問に答えられないエンジニアが多い。

`INITIAL`属性一つとっても、当時のメモリ制約やCPUコストを考慮した先人たちの設計思想が詰まっている。単に新しい言語に置き換えるだけでなく、こうした「コンパイラが裏で何をしているか」を理解しておくことは、システムアーキテクトとして非常に強力な武器になる。

まとめ:明日からのコーディング標準

1. 頻繁に呼び出されるプロシージャでは、`INITIAL`の使用を控える。
2. 大規模配列の初期化は`ASSIGN`代入や、必要に応じて`PLIFILL`等の組み込み関数(BUILTIN)を活用する。
3. `ON`ユニット内での変数参照は、スコープを明示的にし、不要なスタック操作を避ける。

メインフレームは、正直なシステムだ。コードを簡潔に、そしてコンパイラの挙動を尊重して書けば、それに応えて圧倒的なパフォーマンスを提供してくれる。もし君の担当しているバッチが重いと感じたら、まずはソースコードを眺め、「この初期化は本当に毎回必要なのか?」と自問自答してみてほしい。

それだけで、システムの応答時間は劇的に変わるはずだ。健闘を祈る。

タイトルとURLをコピーしました