RPG 命令を使用したデフォルト・ヒープの管理
活動化グループ内で動的記憶域の最初の要求があると、デフォルト・ヒープが作成され、 ここから記憶域割り振りが行われます。 動的記憶域の追加の要求は、デフォルト・ヒープからの割り振りによって満たされます。 動的記憶域の現行要求を満たすための記憶域がヒープに不足している場合には、 ヒープが拡張され、追加の記憶域が割り振られます。
割り振られた動的記憶域は、明示的に解放するか、あるいはヒープが破棄されるまで割り振られたままです。 デフォルト・ヒープが破棄されるのは、所有する活動化グループが終了したときだけです。
同一の活動化グループのプログラムはすべて、同じデフォルト・ヒープを使用します。 あるプログラムが割り振られた以上の記憶域をアクセスした場合には、 別のプログラムに問題を起こすことがあります。 例えば、2 つのプログラム、PGM A と PGM B が同じ 活動化グループで実行されているものとします。10 バイトが PGM A に割り振られても 11 バイト が PGM A で変更されています。 もし PGM B にエクストラ・バイトが実際に割り振られていた場合は、PGM B に問題が起こります。
デフォルト・ヒープでは次の RPG 命令を使用することができます。
- ALLOC 命令コードおよび %ALLOC 組み込み関数は、デフォルト・ヒープ内に記憶域を割り振ります。
- DEALLOC 命令コードは、ヒープ記憶域の 1 つ前の割り振りを解放します。
- REALLOC 命令コードおよび %REALLOC 組み込み関数は、あらかじめヒープから割り振られている記憶域のサイズを変更します。
注: ALLOC および %ALLOC
が処理するのはデフォルト・ヒープだけですが、DEALLOC、REALLOC、および
%REALLOC はデフォルト・ヒープとユーザー作成ヒープの両方を処理します。
図 1 は、名前のリンク・リストを作るために記憶域管理命令コードがどのように使われるかを示します。
図 1. メモリー管理 - 名前のリンク・リストの作成
*-----------------------------------------------------------------*
* このモジュール内のサブプロシージャーのプロトタイプ *
*-----------------------------------------------------------------*
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: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