CICSとPL/Iの「メモリの二重支配」を解く:動的ストレージ管理の深淵
基幹系システムの現場で、多くのアーキテクトが「悪夢」を見る瞬間がある。それは、CICSのオンライン処理が理由不明のアベンド(ASRA/ASRB)で停止し、PL/Iのストレージ管理領域が破壊されている事実に直面した時だ。
特に、PL/Iの `ALLOCATE` ステートメントと、CICSの `EXEC CICS GETMAIN` を不用意に混在させる実装は、地雷原を歩くようなものだ。今日は、この「メモリの二重支配」がなぜ危険なのか、そして我々移行スペシャリストがどう向き合うべきかについて、現場の視点で切り込む。
—
1. なぜ「PL/IのALLOCATE」と「CICS GETMAIN」は相性が悪いのか
PL/Iの `ALLOCATE` は、PL/Iランタイム(PL/I Library)が管理するヒープ領域からメモリを切り出す。一方、`EXEC CICS GETMAIN` は、CICSのタスク制御領域(TCA)配下のストレージ・マネージャが直接メモリを割り当てる。
ここでの最大のリスクは、「メモリ管理のオーナーシップ」が完全に分離していることだ。
例えば、`ALLOCATE` で確保した領域を解放(`FREE`)し忘れたまま、CICS側でメモリを操作し、そのポインタをPL/I側に渡すような設計を行うと、PL/Iの `AUTOMATIC` 変数や `BASED` 変数の管理用ブロックが破壊される。これが発生すると、次に `ALLOCATE` が呼ばれた瞬間に、無関係な箇所で `STORAGE EXCEPTION` が発生する。ダンプを追っても、犯人は遥か手前の「メモリ破壊」という、特定が困難な事象に突き当たる。
危険な実装例:ポインタの不整合
1
/ ポインタ変数の定義 /
DCL P_PTR POINTER;
DCL 1 B_STRUCT BASED(P_PTR),
2 FIELD1 CHAR(10),
2 FIELD2 FIXED BIN(31);
/ 危険な設計:CICSで確保した領域をPL/Iの構造体に強引にマッピング /
EXEC CICS GETMAIN SET(P_PTR) LENGTH(20) SHARED;
/ ここでPL/Iのランタイム管理外の領域を操作するため、 /
/ 将来的にPL/IのALLOCATEがこの領域を再利用しようとして競合する可能性がある /
B_STRUCT.FIELD1 = ‘DATA_SYNC’;
—
2. 実務におけるダンプ解析とエッジケースの回避
もし貴方のシステムで、CICSトランザクションが不可解な `SOC4` アベンドを吐き出しているなら、まずは PL/Iの `CHECK(STORAGE)` コンパイラオプション を検討してほしい。これはパフォーマンスを犠牲にするが、境界外アクセスを即座に検知する。
また、マイグレーションの文脈で注意すべきは「パックデシマル(FIXED DEC)の内部表現」だ。PL/Iは内部的にパックデシマルを使用するが、Java等にデータを引き渡す際、符号(Sign)ビットの反転(C/D/F)処理を疎かにすると、メインフレーム側のデータが壊れたまま他プラットフォームへ流出する。
信頼性を担保するための設計指針
1. 管理の統一: CICS環境下では、可能な限り `EXEC CICS GETMAIN` に一本化する。PL/Iの `ALLOCATE` は、非オンライン(バッチ)処理でのみ許可するという境界線(Boundary)を明確に引くべきだ。
2. ストレージ・キーの意識: CICSのストレージ保護(Storage Protection)を有効にしている場合、ユーザーキーとCICSキーの境界を跨ぐようなポインタ操作は絶対に避けること。
3. DB2との連携: `EXEC SQL` を利用する場合、SQLDA(SQL Descriptor Area)のメモリ割り当てに `ALLOCATE` を使うのは定石だが、必ず `FREE` を保証する `ON-UNIT` を設定すること。
1
/ 安全なメモリ管理のためのON-UNIT活用 /
ON ERROR BEGIN;
PUT SKIP LIST(‘システムエラー発生: メモリ解放を試行中…’);
IF P_PTR ^= NULL() THEN FREE B_STRUCT;
EXIT;
END;
/ 領域確保と初期化 /
ALLOCATE B_STRUCT;
/ ここで確実に処理を行い、直後にFREEを呼ぶのが基幹系の鉄則 /
—
3. レガシー移行期における「脱・依存」へのロードマップ
JavaやC#へのマイグレーションを担当するアーキテクト諸君に伝えたい。PL/Iのコードをそのまま他言語に翻訳するだけでは、この「メモリ管理の暗黙の了解」は再現できない。
移行先で同様のバグを発生させないためには、「メモリ管理を言語ランタイムに依存させず、明示的なオブジェクトライフサイクル管理(スコープ内での確保と解放)に置き換える」ことだ。特に、CICSの `GETMAIN` に相当する機能は、Javaであれば `ThreadLocal` なメモリプールや、ガベージコレクションを考慮したバッファ管理に変換する必要がある。
最後に
PL/Iという言語は、非常に「自由」だ。その自由さは、かつてメインフレームという極限の計算リソースを使い切るための武器だった。しかし、現代のアーキテクチャでは、その自由さは「リスク」に変わる。
システムアーキテクトの仕事は、コードを書くことではない。コードが持つ「暗黙の規約」を言語化し、次世代のプラットフォームでも揺るがない「堅牢な構造」へと昇華させることだ。アベンドのダンプを読み解く苦労は、次のシステムをより強固にするための糧となる。
基幹システムの番人として、諸君の健闘を祈る。
