RPG 命令を使用したデフォルト・ヒープの管理

活動化グループ内で動的記憶域の最初の要求があると、デフォルト・ヒープが作成され、 ここから記憶域割り振りが行われます。 動的記憶域の追加の要求は、デフォルト・ヒープからの割り振りによって満たされます。 動的記憶域の現行要求を満たすための記憶域がヒープに不足している場合には、 ヒープが拡張され、追加の記憶域が割り振られます。

割り振られた動的記憶域は、明示的に解放するか、あるいはヒープが破棄されるまで割り振られたままです。 デフォルト・ヒープが破棄されるのは、所有する活動化グループが終了したときだけです。

同一の活動化グループのプログラムはすべて、同じデフォルト・ヒープを使用します。 あるプログラムが割り振られた以上の記憶域をアクセスした場合には、 別のプログラムに問題を起こすことがあります。 例えば、2 つのプログラム、PGM A と PGM B が同じ 活動化グループで実行されているものとします。10 バイトが PGM A に割り振られても 11 バイト が PGM A で変更されています。 もし PGM B にエクストラ・バイトが実際に割り振られていた場合は、PGM B に問題が起こります。

デフォルト・ヒープでは次の RPG 命令を使用することができます。

注:
ALLOC および %ALLOC が処理するのはデフォルト・ヒープだけですが、DEALLOC、REALLOC、および %REALLOC はデフォルト・ヒープとユーザー作成ヒープの両方を処理します。

図 53 は、名前のリンク・リストを作るために記憶域管理命令コードがどのように使われるかを示します。

図 53. メモリー管理 - 名前のリンク・リストの作成
      *-----------------------------------------------------------------*
      * このモジュール内のサブプロシージャーのプロトタイプ              *
      *-----------------------------------------------------------------*
     D AddName         PR
     D   name_parm                   40A
     D Display         PR
     D Free            PR
      *-----------------------------------------------------------------*
      * リスト内の各要素には、名前へのポインターと次の要素への          *
      * ポインターが含まれています。                                    *
      *-----------------------------------------------------------------*
     D elem            DS                  BASED(elem@)
     D   name@                         *
     D   next@                         *
     D   name_len                     5U 0
     D nameVal         S             40A    BASED(name@)
     D elemSize        C                   %SIZE(elem)
      *-----------------------------------------------------------------*
      * リストの最初の要素は静的記憶域にあります。                      *
      * この要素の名前のフィールドには値を設定しません。                *
      *-----------------------------------------------------------------*
     D first           DS
     D                                 *   INZ(*NULL)
     D                                 *   INZ(*NULL)
     D                                5U 0 INZ(0)
      *-----------------------------------------------------------------*
      * これは現在の要素へのポインターです。                            *
      * elem@ を <first> のアドレスに設定すると、                       *
      * リストは空になります。                                          *
      *-----------------------------------------------------------------*
     D elem@           S               *   INZ(%ADDR(first))
      *-----------------------------------------------------------------*
      * リスト内の 5 つの要素を書き込みます。                           *
      *-----------------------------------------------------------------*
     C                   DO        5
     C     'Name?'       DSPLY                   name             40
     C                   CALLP     AddName(name)
     C                   ENDDO

      *-----------------------------------------------------------------*
      * リストを表示した後で、このリストを解放します。                  *
      *-----------------------------------------------------------------*
     C                   CALLP     Display
     C                   CALLP     Free
     C                   EVAL      *INLR = '1'

      *-----------------------------------------------------------------*
      * サブプロシージャー                                              *
      *-----------------------------------------------------------------*
      *-----------------------------------------------------------------*
      * AddName - リストの末尾に名前を追加します                        *
      *-----------------------------------------------------------------*
     P AddName         B
     D AddName         pi
     D   name                        40A
      *-----------------------------------------------------------------*
      * リストの現在の末尾の「次の」ポインターが指す新しい要素を        *
      * 配列に割り振ります。                                            *
      *                                                                 *
      * 割り振り前:                                                     *
      *                                                                 *
      *  .-------------.                                                *
      *  |             |                                                *
      *  | name     *--->abc                                            *
      *  | name_len 3  |                                                *
      *  | next     *-------|||                                         *
      *  |             |                                                *
      *  '-------------'                                                *
      *                                                                 *
      *-----------------------------------------------------------------*
     C                   ALLOC     elemSize      next@
      *-----------------------------------------------------------------*
      *                                                                 *
      * 割り振り後: elem@ がまだ元の要素を指しているため、まだ          *
      *             その元の要素が現在の要素のままであることに          *
      *             注意してください                                    *
      *                                                                 *
      *  .-------------.               .--------------.                 *
      *  |             |       .------>|              |                 *
      *  | name     *--->abc   |       |              |                 *
      *  | name_len 3  |       |       |              |                 *
      *  | next     *----------'       |              |                 *
      *  |             |               |              |                 *
      *  '-------------'               '--------------'                 *
      *                                                                 *
      * ここで、elem@ が新しい要素を指すように設定します                *
      *-----------------------------------------------------------------*
     C                   EVAL      elem@ = next@
      *-----------------------------------------------------------------*
      *                                                                 *
      * 設定後: これで、name@、name_len および next@ という名前が       *
      *         新しい要素にある記憶域を指すようになります。            *
      *                                                                 *
      *  .-------------.               .--------------.                 *
      *  |             |       .------>|              |                 *
      *  |          *--->abc   |       | name      *  |                 *
      *  |          3  |       |       | name_len     |                 *
      *  |          *----------'       | next      *  |                 *
      *  |             |               |              |                 *
      *  '-------------'               '--------------'                 *
      *                                                                 *
      * ここで新しい要素の値を設定します。                              *
      * 次のポインターを *NULL に設定して、リストの末尾であることを     *
      * 指定します。                                                    *
      *-----------------------------------------------------------------*
     C                   EVAL      next@ = *NULL
      *-----------------------------------------------------------------*
      * 名前の長さを保管します (末尾のブランクはカウントしません)
      *-----------------------------------------------------------------*
     C                   EVAL      name_len = %len(%trimr(name))
      *-----------------------------------------------------------------*
      * 記憶域を名前に割り振った後に、名前の値に設定します。
      *
      *-----------------------------------------------------------------*
     C                   ALLOC     name_len      name@
     C                   EVAL      %SUBST(nameVal:1&gml.name_len) = name
      *-----------------------------------------------------------------*
      *                                                                 *
      * 設定後:                                                         *
      *                                                                 *
      *  .-------------.               .--------------.                 *
      *  |             |       .------>|              |                 *
      *  |          *--->abc   |       | name      *--->newname         *
      *  |          3  |       |       | name_len  nn |                 *
      *  |          *----------'       | next      *--->|||             *
      *  |             |               |              |                 *
      *  '-------------'               '--------------'                 *
      *-----------------------------------------------------------------*
     P AddName         E
      *-----------------------------------------------------------------*
      * 表示 - リストを表示します                                       *
      *-----------------------------------------------------------------*
     P Display         B
     D saveElem@       S               *
     D dspName         S             40A
      *-----------------------------------------------------------------*
      * 現在の elem ポインターを保管して、表示した後に復元できるように  *
      * します。                                                        *
      * リスト・ポインターをリストの先頭に設定します。                  *
      *-----------------------------------------------------------------*
     C                   EVAL      saveElem@ = elem@
     C                   EVAL      elem@ = %ADDR(first)
      *-----------------------------------------------------------------*
      * 次のポインターが                                                *
      * *NULL になるまで、リストの要素をループします。                  *
      *-----------------------------------------------------------------*
     C                   DOW       next@ <> *NULL
     C                   EVAL      elem@ = next@
     C                   EVAL      dspName = %SUBST(nameVal:1:name_len)
     C     'Name: '      dsply                   dspName
     C                   ENDDO
      *-----------------------------------------------------------------*
      * リスト・ポインターを元の場所に復元します。
      *-----------------------------------------------------------------*
     C                   EVAL      elem@ = saveElem@
     P Display         E
      *-----------------------------------------------------------------*
      * 解放 - リストが使用した記憶域を解放します                       *
      *-----------------------------------------------------------------*
     P Free            B
     D prv@            S               *
      *-----------------------------------------------------------------*
      * リスト内の最初の実要素から開始し、次のポインターが *NULL に     *
      * なるまで、リストの要素をループします。                          *
      *-----------------------------------------------------------------*
     C                   EVAL      elem@ = %ADDR(first)
     C                   EVAL      elem@ = next@
     C                   DOW       elem@ <> *NULL
      *-----------------------------------------------------------------*
      * 名前の記憶域を解放します                                        *
      *-----------------------------------------------------------------*
     C                   DEALLOC                 name@
      *-----------------------------------------------------------------*
      * 現在の elem@ へのポインターを保管します                         *
      *-----------------------------------------------------------------*
     C                   EVAL      prv@ = elem@
      *-----------------------------------------------------------------*
      * elem@ を次の要素に進めます
      *-----------------------------------------------------------------*
     C                   EVAL      elem@ = next@

      *-----------------------------------------------------------------*
      * 現在の要素の記憶域を解放します
      *-----------------------------------------------------------------*
     C                   DEALLOC                 prv@
     C                   ENDDO

      *-----------------------------------------------------------------*
      * 新しいリストの準備をします
      *-----------------------------------------------------------------*
     C                   EVAL      elem@ = %ADDR(first)
     P Free            E