サブプール:仮想記憶内の分類された区域

OSは、仮想記憶域をその利用目的などに応じて分類・管理しています。MVSでは、分類された領域(区域)をサブプールと呼び、各サブプールには識別のための0~255までの番号が付けられています。どのサブプールを使うかはGETMAINやSTORAGEマクロ、あるいはCPOOLマクロでサブプール番号を指定することで決まります。一般のユーザープログラムが利用できるのは0~127、131、132です。128以上、特に200番以上はSQA、CSA、LSQAと言ったシステムが制御用に使用する領域ともなっています。デフォルトのサブプールは0番となります。なお、サブプール番号によって仮想記憶域を区分けして使用するのはアセンブラー・プログラムに限ります。

各サブプールには次に示す属性が割り当てられています。プログラムが利用する領域がどのような属性を持っていればいいのかに合わせて、適切なサブプールを選択します。

  • 仮想記憶内の位置
  • 利用する領域が、低位アドレスPVT、高位アドレスPVT、LSQA、CSA、SQAのどこに属する領域かを示します。低位・高位の区別は、16MB境界の上下ではありません。16MB上下それぞれのプライベート領域の低いアドレスから割り当てるのか、高いアドレスから割り当てるのかです。例えば、5000番地から割り当てるのか、F00000番地から割り当てるのかと言うことです。

  • 記憶保護キー
  • 領域が持つ記憶保護キーです。当然ながらプログラムが持つPSWのキーと一致するか、あるいは矛盾が無いようにしなければなりません。GETMAINされる領域のキーは、サブプールによって要求元プログラムのPSWキー、要求元プログラムのジョブステップ・キー、パラメーターで選択、常に0などに分かれます。

  • フェッチプロテクション
  • 領域に読み出し保護が掛かるかどうかです。CPU命令ではキーが異なっても書き込みでなければアクセスが許されますが、読み出し保護が掛かっている領域ではキーが一致しないと読み出しすらできません。

  • ページ固定
  • 領域がページング可能なのかページ固定されるかです。

  • 領域の所有者
  • 領域の所有者は、その領域の返却責任者でもあり仮想記憶内の位置と関連します。タスク、ジョブステップ・タスク、アドレス空間、システムに分かれます。プログラムがFREEMAINマクロを使用するなど明示的に解放しない場合、オーナーが終了する時にシステムによって解放されます。タスクが所有者ならタスク終了時に未解放の領域は自動的に返却されます。CSAやSQAなどの共通域のオーナーはシステムです。GETMAINしたジョブがFREEMAINしないで終わっても自動的に解放されません。

仮想記憶を構成するサブプールの要約表は、z/OSのしくみ:基礎編:データセットの種類とアクセス方式の記事の「サブプールと記憶保護キー」に記載してあります。サブプールの詳細については、下記のマニュアルが参考にできます。

  • MVS:「z/OS MVS Programming: Authorized Assembler Services Guide」
  • MSP:「システムプログラミング手引書 タスク管理編 -OS IV/MSP-」
  • VOS3:「システムプログラマの手引 -マクロ編-」

追加の解説

  • サブプールを分ける効果
  • 一般のプログラムはサブプールを特に意識しなくてもいいのですが、サブプールを分けることで仮想記憶域の使用効率を高めることができます。例えば、処理Aで4000バイトの領域を確保した後、処理Bで50バイトを確保したとします。それぞれの領域は同じサブプール0から確保されます。それぞれの領域があるページをページ1とします。その後、処理Aで別の領域を60バイト確保すると、新たなページであるページ2が切り出されてそこから60バイトが確保されます。その状態で処理Bが終わり使用済みの50バイト領域が解放されても、処理Aによってページ1では4000バイト、ページ2では60バイトが使われていて、ページ1とページ2の2つのページが使われたままです。
    異なるサブプールが同じページに混在することはないので、処理Aと処理Bでサブプールを1と2に分けると、処理Bで使用する50バイトは処理Aとは別のページに割り当てられます。そのため、処理Aではサブプール1であるページ1に4000と60バイト、処理Bではサブプール2であるページ2に50バイトが使われることになります。処理Bが終わればページ2は返却されるため、残るページは1だけになります。したがって、空間が使っているページは1個減ります。リアルメモリーも1ページ分減りますからワーキングセットも小さくなります。
    合計で使用する仮想記憶量を減らすことにはならなくても、サブプールを上手に使い分けることでページの利用効率を高めて、実記憶の使用量であるワーキングセットを小さくできることに繋がります。

  • ロードモジュールのサブプール
  • ロードモジュールは、サブプール251または252にローディングされます。モジュールがAPF許可ライブラリーにあって、リエントラント・プログラムとしてリンケージされている場合はサブプール252です。サブプール252はキー0の領域なので、APF許可された再入可能モジュールは書き込みから保護されます。そのため、ロジック自体は再入可能になっていても、処理の必要からモジュール内に書き込み(例えば、初回コールの時だけアンカーポイントを設定する等)を行うようなプログラムは、改版などによってAPFが必要な機能を追加した途端にS0C4でABENDするようなことが起き得ます。ISVにいた時、同様の経験がありました。なお、TSOではコマンド・プログラムとCALLコマンドで呼び出されるプログラムは、APFでなくてもRENT属性であればサブプール252にローディングされます。

  • キー0のプログラムによるサブプール0へのGETMAIN
  • キー0でスーパーバイザーモードのプログラムがサブプール0にGETMAINすると、実際の領域はサブプール252から獲得されます。領域の記憶保護キーは0です。そのため、ユーザーSVCルーチンなどを使用する際、SVCの呼び出し側とSVCルーチンで共用する領域をSVCルーチン側で確保する場合は注意が必要です。
    SVCルーチンに限らず、キー0スーパーで動くプログラムがジョブステップのキー(8)で領域を確保する場合は、サブプール250を指定します。この場合、OSはサブプール250をサブプール0に変換して領域を確保します。解放時も同じです。

  • サブプールの共用
  • サブプール0はタスク間で共用されます。0以外のサブプールは共用されません。なお、ここで言う共用とは「誰がその領域を返却できるのか?」と言うことです。同じ空間内なので、各タスクは他のタスクが確保した領域であってもアドレスさえ指定すれば自由に読み書きできますが、返却に関しては領域を確保したタスクに限られます。共用可能なサブプールのみが他のタスクが確保した領域を返却できることになるのです。例えば、メインタスクで確保した領域をサブタスクで解放するような場合は共用サブプールを使わねばなりません。そのためにはサブタスクをATTACHする際に、共用するサブプール番号をパラメーターで指定する必要があります。また逆に、暗黙の共用サブプールであるサブプール0を共用しないように指定することもできます。OSのユーティリティーをプログラムから繰り返し呼び出すような場合、LINKマクロを使うのではなく、サブプール0を共用しないサブタスクとしてATTACHすれば、仮にユーティリティー側でGETMAINした領域が未返却のままであっても、OSがサブタスク終了時に使用済みのサブプール0を解放してくれます。