malloc サブシステムを使用したシステム・メモリーの割り当て

メモリーは、malloc サブシステムを使用してアプリケーションに割り当てられます。

malloc サブシステムは、以下のサブルーチンから構成されるメモリー管理 API です。

  • malloc
  • calloc
  • realloc
  • free
  • mallopt
  • mallinfo
  • alloca
  • valloc
  • posix_memalign

malloc サブシステムは、ヒープ と呼ばれる論理メモリー・オブジェクトを管理します。 ヒープとは、コンパイラーによって割り当てられたデータの最後のバイトと、データ領域 の終わりの間の、アプリケーションのアドレス・スペースに常駐するメモリーの領域のことです。 ヒープは、メモリーの割り当て元であり、メモリーが malloc サブシステム API によって戻される 先であるメモリー・オブジェクトです。

malloc サブシステムは、以下の基本的なメモリー操作を実行します。
  • 割り当て:

    malloccallocvallocalloca、 および posix_memalign サブルーチンによって実行されます。

  • 割り当て解除:

    free サブルーチンによって実行されます。

  • 再割り当て:

    realloc サブルーチンによって実行されます。

mallopt および mallinfo サブルーチンは、システム V 互換用にサポートされます。 プログラム開発の際に mallinfo サブルーチンを 使用すると、malloc サブルーチンによって管理される ヒープに関する情報を入手することができます。 mallopt サブルーチンを使用して、ページ位置合わせされ、かつページ・サイズの設定されたフリー・メモリーを破棄し、デフォルトのアロケーターを使用可能/使用不可にすることができます。 malloc サブルーチン同様、valloc サブルーチンは、バークレー互換ライブラリーとの互換性のために提供されています。

詳しくは、以下のセクションを参照してください。

プロセス・ヒープの処理

_edata は、初期化されたプログラム・データの最後のバイトに続く最初のバイトのアドレスのシンボルです。 _edata シンボルは、プロセス・ヒープの先頭を参照します。 プロセス・ヒープは、データの最初のブロックが割り当てられるときに、malloc サブシステムによって拡大されます。 malloc サブシステムは、プロセス・ヒープの最後を示しているプロセス brk 値を増やすことによって、プロセス・ヒープを大きくします。 これは、sbrk サブルーチンを呼び出すことによって行われます。 malloc サブシステムは、アプリケーションの求めに応じて、プロセス・ヒープを拡張します。

プロセス・ヒープは、割り当て済み解放されたメモリー・ブロックに分かれます。 フリー・プールは、次の割り当てに使用できるメモリーから構成されます。 割り当ては、まずメモリー・ブロックをフリー・プールから除去し、 次に呼び出し元の関数にこのブロックを指すポインターを戻すことによって完了します。 再割り当ては、新規サイズのメモリー・ブロックを割り当て、 元のブロック内のデータを新規ブロックに移動し、 そして元のブロックを解放することによって完了します。 割り当てられたメモリー・ブロックは、 アプリケーションが使用するプロセス・ヒープの断片から構成されます。 メモリー・ブロックは、ヒープから物理的に 除去されるわけではないので (状態がフリーから割り当て済み に変わるだけ)、プロセス・ヒープのサイズは、 メモリーがアプリケーションから解放されても減りません。

32 ビット・アプリケーションでのプロセス・アドレス・スペース

システムで実行される 32 ビット・アプリケーション・プログラムには、 以下のセグメントに分割されるアドレス・スペースがあります。

セグメント 説明
0x00000000 から 0x0fffffff カーネルが含まれています。
0x10000000 から 0x1fffffff アプリケーション・プログラム・テキストが含まれています。
0x20000000 から 0x2fffffff アプリケーション・プログラム・データ、プロセス・ヒープ、およびアプリケーション・スタックが含まれています。
0x30000000 から 0xcfffffff 共有メモリー、または mmap サービスで使用可能です。
0xd0000000 から 0xdfffffff 共有ライブラリー・テキストが含まれています。
0xe0000000 から 0xefffffff 共有メモリー、または mmap サービスで使用可能です。
0xf0000000 から 0xffffffff アプリケーションの共有ライブラリー・データが含まれています。

64 ビット・アプリケーションでのプロセス・アドレス・スペース

システムで実行される 64 ビット・アプリケーション・プログラムには、 以下のセグメントに分割されるアドレス・スペースがあります。

セグメント 説明
0x0000 0000 0000 0000 から 0x0000 0000 0fff ffff カーネルが含まれています。
0x0000 0000 f000 0000 から 0x0000 0000 ffff ffff 予約済みです。
0x0000 0001 0000 0000 から 0x07ff ffff ffff ffff アプリケーション・プログラム・テキスト、アプリケーション・プログラム・データ、プロセス・ヒープ、 および、共有メモリーまたは mmap サービスが含まれています。
0x0800 0000 0000 0000 から 0x08ff ffff ffff ffff 私用としてロードされるオブジェクトです。
0x0900 0000 0000 0000 から 0x09ff ffff ffff ffff 共有ライブラリー・テキストおよびデータです。
0x0f00 0000 0000 0000 から 0x0fff ffff ffff ffff アプリケーション・スタックです。
注: AIX® は、アプリケーションに 割り当てられたストレージに、遅延ページング・スロット割り当て技法を使用します。 malloc などのサブルーチンによって、ストレージがアプリケーションに割り当てられたときに、そのストレージが参照されるまでは、そのストレージにページング・スペースは割り当てられません。 この技法は、大きくてばらばらなメモリー・セグメントを割り当てるアプリケーションでは有用です。 しかし、この技法は非常に多くのメモリーを割り当てるアプリケーションのポータビリティーに影響を及ぼすことがあります。 メモリー要求をサポートするだけの十分なバッキング・ストレージがないときに、malloc 呼び出しが失敗することを想定しているアプリケーションの場合、そのアプリケーションは多過ぎるメモリーを割り当てることがあります。 このメモリーが後で参照されたときに、マシンはすぐにページング・スペースを使い尽くすので、オペレーティング・システムはプロセスを強制終了させて、システムが完全に仮想メモリーを使い尽くさないようにします。 メモリーを割り当てるアプリケーションは、割り当てるストレージ用にバッキング・ストレージが存在することを確認する必要があります。 PSALLOC 環境変数を PSALLOC=early に設定すると、ページング・スペース割り当て技法が早期割り当てアルゴリズムに変更されます。 早期割り当てでは、ページング・スペースはメモリーが要求されるとすぐに割り当てられます。 詳しくは、「オペレーティング・システムおよびデバイスの管理」の『ページング・スペースおよび仮想メモリー』を参照してください。

システム割り当てポリシーについて

割り当てポリシー とは、ヒープを表し、割り当て、割り当て解除、および再割り当てを行う際に使用する、データ構造とアルゴリズムのセットのことです。 malloc サブシステムは、いくつかの異なる割り当てポリシー (デフォルト割り当てポリシー、Watson 割り当てポリシー、malloc 3.1 割り当てポリシー、およびユーザー定義割り当てポリシー) をサポートします。 malloc サブシステムをアクセスするための API は、その基礎であるインプリメンテーションが異なるだけで、すべての割り当てポリシーで同じです。

以下の環境変数を使用して、割り当てポリシーとそのポリシーでの通常オプションまたはデバッグ・オプションを指定します。
  • MALLOCTYPE は割り当てポリシーを指定します。
  • MALLOCOPTIONS は選択した割り当てポリシーの通常オプションを指定します。
  • MALLOCDEBUG は選択した割り当てポリシーのデバッグ・オプションを指定します。
  • MALLOCALIGN は、プログラム外部の デフォルトの malloc 位置合わせを指定します。

デフォルト割り当てポリシーは一般に効率がよく、大半のアプリケーションはこちらを選択するほうがよいでしょう。 その他の割り当てポリシーは、動作に何らかの固有の特徴がありますが、 『各種の割り当てポリシーの比較』に説明されているように、特定の環境では効果的なこともあります。

さまざまな割り当てポリシーのいくつかのオプションは、互いに互換性があるので、 タンデムに使用することができます。 オプションをタンデムに使用する場合は、コンマ (,) を使用して、MALLOCOPTIONS および MALLOCDEBUG 環境変数で指定するオプションを区切ります。

MALLOCALIGN 環境変数を、すべて の malloc() 割り当てに必要なデフォルト位置合わせ に設定することができます。 例を以下に示します。
MALLOCALIGN=16;  export MALLOCALIGN
MALLOCALIGN 環境変数は、対応する実行モードでポインターのサイズより大か等しい、任意の 2 の累乗値に設定することができます (32 ビット・モードの場合は 4 バイト、64 ビットの場合は 8 バイト)。 32 ビットのベクトル対応プログラム の場合、この環境変数は 16 に設定することができ、このため すべての malloc() は、必要であればベクトルのデータ型にぴったり位置合わせできます。 64 ビットのベクトル・プログラムは 16 バイト境界に位置合 わせして割り当て済みになることに注意してください。

また、プログラム内部では、そのプログラムは mallopt(M_MALIGN, 16) ルーチンを使用して、16 バイトに位置合わせして割り当てを行うように、デフォルトの malloc() を変更することができます。 mallopt(M_MALIGN) ルーチンにより、プログラムはデフォルトの malloc 位置合わせを実行時に動的に制御することができます。

デフォルト割り当てポリシーについて

デフォルト割り当てポリシーは、カルテシアン・バイナリー・サーチ・ツリー内のノードとしてヒープ内のフリー・スペースを維持します。このツリーの中でノードは、アドレス順に左から右へ (アドレスは右側が大きくなる)、長さ順に上から下へ (子はその親より大きくならない) 並べられています。 このデータ構造では、ツリーによってサポートされるブロック・サイズ数に制限はなく、考えられる 広い範囲のブロック・サイズを使用することができます。 ツリー再編成技法を用いると、ノードの検索、追加、および削除に要するアクセス時間を最適化し 、フラグメント化に対する保護も行います。

デフォルト割り当てポリシーには、オプションとして以下の機能があります。

割り当て

割り当て要求をサービスするには、少しのオーバーヘッドが必要になります。 これは、メタデータ・プレフィックスが必要なためと、各メモリー・ブロックの適切な調整が必要なためです。 すべての割り当てでのメタデータ・プレフィックスのサイズは、8 バイト (32 ビット・プログラム) および 16 バイト (64 ビット・プログラム) です。 各ブロックは、16 または 32 バイト境界に位置合わせされている必要があります。したがって、サイズ n の割り当てに必要なメモリーの総量は次のようになります。

size = roundup(n + prefix_size, alignment requirement)

例えば、32 ビット・プロセスでサイズ 37 を割り当てると、roundup(37 + 8, 16)、すなわち 48 バイトが必要になります。

必要なサイズ以上の最低アドレスを持ったツリー・ノードは、ツリーから除去されます。 検出されたブロックが必要なサイズを超えている場合、 そのブロックは、2 つのブロック、 すなわち必要なサイズのブロックと残りのブロックに分割されます。 2 番目のブロックは、runt と呼ばれ、 フリー・ツリーに戻されて将来の割り当てに使用されます。 最初のブロックは呼び出し元に戻されます。

フリー・ツリー内で十分なサイズのブロックが検出されない場合は、ヒープは拡張され、獲得された 拡張のサイズを持つブロックがフリー・ツリーに追加され、 割り当ては上記の説明のように継続します。

割り当て解除

free サブルーチンによって割り当て解除 されたメモリー・ブロックは、ツリーのルートに戻されます。 新規ノードの挿入ポイントまでのパスに沿った各ノードが検査されて、 挿入されるノードに隣接していないかどうかが調べられます。 隣接している場合は、2 つのノードは組み合わされ、 新たに組み合わされたノードはツリー内に再配置されます。 隣接ブロックが見つからなければ、ノードは、 ツリー内の適切な場所に挿入されるだけです。 隣接ブロックをマージすると、ヒープのフラグメント化を大幅に減らすこ とができます。

再割り当て

再割り当てブロックのサイズが元のサイズを上回る場合は、 free サブルーチンによって 元のブロックをフリー・ツリーに戻し、合体が起こり得るようにします。 これで、要求されたサイズの新規ブロックが割り当てられて、 データは元のブロックから新しいブロックに移動され、 新しいブロックがコール元に戻されます。

再割り当てブロックのサイズが元のブロックより小さいと、 ブロックは分割されて、より小さいブロックがフリー・ツリーに戻されます。

制限

デフォルト割り当てポリシーは、以下のオプションをサポートします。

Watson 割り当てポリシーについて

Watson 割り当てポリシーは、2 つの個別の red-black ツリー (1 つはアドレス順に、もう 1 つはサイズ順にソートされている) 内のノードとしてヒープ内のフリー・スペースを維持します。 Red-black ツリーは、デフォルト・アロケーターのカルテシアン・ツリーより簡素で効率的なツリー操作を提供します。 したがって、Watson 割り当てポリシーは、多くの場合、デフォルト割り当てポリシーより高速です。

割り当て

Watson 割り当てポリシーには、デフォルト割り当てポリシーと同じオーバーヘッド要件があります。

サイズ・ツリーを検索して、必要なサイズ以上で最小の可能なブロックを探します。 そして、そのブロックをサイズ・ツリーから除去します。 見付かったブロックが必要なサイズを超えている場合、 そのブロックは 2 つのブロック、すなわち残りの 1 つのブロックと必要なサイズの 2 つ目のブロックに分割されます。 最初のブロックは、runt と呼ばれ、サイズ・ツリーに戻されて将来の割り当てに使用されます。 2 番目のブロックは呼び出し元に戻されます。 サイズ・ツリー内で見付かったブロックがぴったりと要求されたサイズであった場合は、そのブロックはサイズ・ツリーとアドレス・ツリーの両方から除去されて、呼び出し元に戻されます。

フリー・ツリー内で十分なサイズのブロックが見付からない場合は、プロセス・ヒープが拡張され、この拡張のサイズを持つブロックが サイズ・ツリーとアドレス・ツリーに追加され、割り当ては上記の説明のように継続します。

割り当て解除

free サブルーチンによって割り当て解除 されたメモリー・ブロックは、アドレス・ツリーのルートに戻されます。 新規ノードの挿入ポイントまでのパスに沿った各ノードが検査されて、 挿入されるノードに隣接していないかどうかが調べられます。 隣接している場合は、2 つのノードは組み合わされ、 新たに組み合わされたノードはサイズ・ツリー内に再配置されます。 隣接ブロックが見付からない場合は、ノードは、 アドレス・ツリーとサイズ・ツリーの両方で適切な場所に単に挿入されます。

挿入後、両方の red-black ツリーは正しくバランスしているか検査される必要があります。

再割り当て

再割り当てブロックのサイズが元のブロックのサイズより大きい場合は、free サブルーチンによって 元のブロックをフリー・ツリーに戻し、合体が起こり得るようにします。 これで、要求されたサイズの新規ブロックが割り当てられて、 データは元のブロックから新しいブロックに移動され、 新しいブロックがコール元に戻されます。

再割り当てブロックのサイズが元のブロックのサイズより小さい場合は、 ブロックは分割されて、残りのブロックがフリー・ツリーに戻されます。

制限

Watson 割り当てポリシーは、以下のオプションをサポートします。

malloc 3.1 割り当てポリシーについて

malloc 3.1 割り当てポリシーは、プロセスを始動するまえに MALLOCTYPE=3.1 を設定することによって選択することができます。 これ以降、シェルによって実行されているすべての 32 ビット・プログラムは、malloc 3.1 割り当てポリシーを使用します (64 ビット・プログラムは継続してデフォルト割り当てポリシーを使います)。

malloc 3.1 割り当てポリシーは、ヒープを、それぞれがリンク・リストを指す、1 組の 28 のハッシュ・バケットとして維持します。 各リンク・リストには、特定サイズのブロックが入っています。 ハッシュ・バケットへの索引は、リンク・リスト内のブロックのサイズを示します。 ブロック・サイズの計算は、次の公式で行われます。
size = 2 i + 4
ここで、i はバケットを識別します。 すなわち、 バケット・ゼロでアンカーされたリストのブロックの長さは 20+4 = 16 バイトであることを意味します。 したがって、接頭部のサイズが 8 バイトとすると、これらのブロックは、 長さが 0 から 8 バイトの間のブロックの要求を満たすことができます。 次の表は、要求されたサイズをバケット間に分散する方法の説明です。
注: このアルゴリズムでは、実際にアプリケーションによって要求される メモリー量の 2 倍の量を使用することができます。 バケットの大きさが 4096 バイトを超えると、サイズが 1 ページあるいはそれより大きい オブジェクトがページ位置合わせされるため、余分な 1 ページが必要です。 接頭部はブロックの直前に付くため、接頭部のためだけに 1 ページ全体が必要です。
バケット ブロック・サイズ マップされるサイズ 使用されるページ
0 16 0. .. 8  
1 32 9 だけです。 .. 24  
2 64 25 ... 56  
3 128 57 ... 120  
4 256 121 ... 248  
5 512 249 ... 504  
6 1K 505 ... 1K-8  
7 2K 1K-7 ... 2K-8  
8 4K 2K-7 ... 4K-8 2
9 8K 4K-7 ... 8K-8 3
10 16K 8K-7 ... 16K-8 5
11 32K 16K-7 ... 32K-8 9
12 64K 32K-7 ... 64K-8 17
13 128K 64K-7 ... 128K-8 33
14 256K 128K-7 ... 256K-8 65
15 512K 256K-7 ... 512K-8 129
16 1M 256K-7 ... 1M-8 257
17 2M 1M-7 ... 2M-8 513
18 4M 2M-7 ... 4M-8 1K + 1
19 8M 4M-7 ... 8M-8 2K + 1
20 16M 8M-7 ... 16M-8 4K + 1
21 32M 16M-7 ... 32M-8 8K + 1
22 64M 32M-7 ... 64M-8 16K + 1
23 128M 64M-7 ... 128M-8 32K + 1
24 256M 128M-7 ... 256M-8 64K + 1
25 512M 256M-7 ... 512M-8 128K + 1
26 1024M 512M-7 ... 1024M-8 256K + 1
27 2048M 1024M-7 ... 2048M-8 512K + 1

割り当て

ブロックのフリー・プールからの割り当ては、まず要求されたバイトをバケット配列の索引に変換することに よって行われます。次の式を用います。

needed = requested + 8

If needed <= 16,
then
bucket = 0

If needed > 16,
then
bucket = (log(needed)/log(2) rounded down to the nearest integer) - 3

バケットによって固定されたリストの各ブロックのサイズは ブロック・サイズ = 2 bucket + 4 です。 バケット内のリストが null ならば、メモリーは sbrk サブルーチンを用いて 割り当てられ、ブロックがリストに追加されます。 ブロック・サイズが 1 ページ未満であると、1 ページが sbrk サブルーチンを用いて割り当てられます。 また、ブロック・サイズをページ・サイズで割ることによって得られた発生ブロック数が リストに追加されます。 ブロック・サイズがページ以上の場合は、 必要なメモリーが sbrk サブルーチンを用いて割り当てられ、 単一ブロックがバケットのフリー・リストに追加されます。 フリー・リストが空でなければ、リストの先頭のブロックが呼び出し元に戻されます。 この場合、リスト上の次のブロックが新しい先頭になります。

割り当て解除

1 ブロックのメモリーがフリー・プールに戻されると、 バケット索引が、割り当ての場合と同じように計算されます。 次に、解放されるブロックが、バケットのフリー・リストの先頭に追加されます。

再割り当て

1 ブロックのメモリーが再割り当てされると、必要なサイズがブロックの既存のサイ ズと比較されます。 単一のバケットで処理されるサイズには種々のものがあるため、新規ブロック・サイズは、 往々にして元のブロック・サイズと同じバケットにマップします。 このような場合は、接頭部の長さが新規サイズを反映するように更新されて、 同じブロックが戻されます。 要求されたサイズが既存のブロックより大きい場合は、 そのブロックは解放され、新しいブロックが新規バケットから割り当てられて、 データが旧ブロックから新規ブロックに移動されます。

制限

MALLOCTYPE=3.1 を設定すると、32 ビット・プログラムの malloc 3.1 ポリシーのみが使用可能になります。 malloc 3.1 ポリシーを使用する 64 ビット・プログラムの場合は、MALLOCTYPE 環境変数を MALLOCTYPE=3.1_64BIT に明示的に設定する必要があります。 この割り当てポリシーは、デフォルトよりも効率が良くないため、通常は使用しないことをお勧めします。

malloc 3.1 割り当てポリシーは、以下のオプションをサポートします。

プール割り当てポリシーについて

Malloc プールは、513 バイトより小さいストレージ・オブジェクトを管理するための libc 関数 malloccallocfreeposix_memalign、および realloc に対するハイパフォーマンスのフロントエンドです。 このパフォーマンスの利点は、より短いパス長さとデータ・キャッシュ使用率の良さから劇的に得られます。 さらに、マルチスレッド・アプリケーションの場合は、アトミック操作を回避するためにスレッド・ローカルのプール・アンカーを使用するという利点があります。このフロントエンドは、現在 libc (yorktownwatson) で提供されている任意のストレージ管理方式と一緒に使用することができます。

malloc プールを使用するには、次のコマンドを実行します。
export MALLOCOPTIONS=pool<:max_size>

このオプションを指定すると、malloc の初期化時にプールのコレクションが作成されます。この場合、各プールは固定サイズのオブジェクトのリンク・リストです。 最小のプールではポインター・サイズのオブジェクトを保持できます (32 ビット・アプリケーションの場合は 8 バイト、64 ビット・アプリケーションの場合は 16 バイトなど)。一連のプールは、サイズが前のプールより大きいポインター・サイズであるオブジェクトに対応します。 すなわち、32 ビット・アプリケーションには 128 プールがあり、64 ビット・アプリケーションには 64 プールがあるということです。 プールのコレクションは、リンク・リストを「アンカー」するポインターの配列として表されます。

Malloc プールはその独自のメモリー、プール・ヒープを使用します。これは標準の malloc とは共有されません。 max_size オプションは、指定されると次に高い 2 MB 値に切り上げられ、プール・ヒープのサイズを制御するために使用されます。 max_size オプションは、10 進数または 16 進数として指定でき、先頭に 0x または 0X が付きます (例えば、export MALLOCOPTIONS=pool:0x1700000 により、max_size は切り上げ後に 24 MB に設定されます)。

32 ビット・アプリケーションの場合、プール・ヒープのサイズは 2 MB から開始します。 さらにストレージが必要な場合、またプール・ヒープ・ストレージの合計が max_size より小さい場合は、追加で 2 MB が獲得されます。 それぞれの 2 MBb 領域は 2 MB 境界にありますが、他の 2 MB 領域に連続している必要はありません。 64 ビット・アプリケーションの場合、max_size の単一の連続プール・ヒープが malloc の初期化時に割り当てられ、拡張されません。 max_size を指定しない場合、デフォルトで 32 ビット・アプリケーションでは 512 MB、64 ビット・アプリケーションでは 32 MB となります。 32 ビットと 64 ビットの両方のモードで、より大きいサイズが指定されると、max_size は 512 MB に設定されます。 より大きいサイズが指定されると、32 ビット・モードでは max_size が 512 MB に設定され、64 ビット・モードでは max_size が 3.7 GB に設定されます。

ストレージの使用率

すべてのプール・アンカーが NULL または空に初期設定されています。 malloc プールが要求にサービスを提供して、対応するプールが空の場合は、1024 バイト境界の連続 1024 バイト・チャンクでプール・ヒープからストレージを割り当てるルーチンが呼び出されます。 要求されたサイズの複数のオブジェクトが「作成」されます。 最初のオブジェクトのアドレスが要求を満たすために戻される一方、他のオブジェクトは互いにリンクし、プール・アンカーに置かれます。 それぞれの 1024 バイト・チャンクでは、補助テーブル内に 2 バイトのエントリーがあり、戻されたオブジェクトのサイズを決定するために free によって使用されます。

オブジェクトが malloc プールによって解放されると、適切なプール・アンカーに単に「プッシュ」されます。 さらに大きいサイズのオブジェクトを作成するためのブロックの合体は試行されません。

この動作により、malloc プールは他の形式の malloc よりも多くのストレージを使用できます。

位置合わせ

malloc()calloc()、および realloc() サブルーチンのデフォルトの位置合わせを指定するには、MALLOCALIGN 環境変数を適切に設定する必要があります。 posix_memalign() サブルーチンは、MALLOCALIGN 環境変数が設定されていなくても引き続き機能します。 MALLOCALIGN が 512 より大きい場合は、malloc プールは使用されません。

キャッシュ効率

malloc pool で割り当てられたメモリー・オブジェクトには、接頭部または接尾部がありません。 このため、データ・キャッシュ・ラインは、アプリケーション使用可能データとともに、より高密度にパックされます。 サイズが 2 の累乗であるメモリー・オブジェクトはそのサイズと等しい境界に位置合わせされるため、各オブジェクトは最小数のキャッシュ・ライン内に格納されます。 malloc サブルーチンと free サブルーチンは、ツリーやリンク・リストをスキャンしないため、キャッシュを「汚染」することはありません。

マルチスレッド・サポート

Malloc プールにより、ロックの競合とアトミック操作の必要性が少なくなるため、マルチスレッドの場合にパフォーマンスが著しく向上します。

ロード・バランシング・サポート

マルチスレッド・シナリオによっては、動的に割り当てられたメモリーの解放が反復されるため、1 つのスレッドの空きプールが非常に大きくなることがあります。しかし、他のスレッドがこのメモリーを使用できるとは限りません。

ロード・バランシング・サポートにより、プールがしきい値に達した後、スレッドは各プールのメモリーの半分をグローバル・プールに解放し、他のスレッドで使用できるようにします。スレッドのプールが再調整されるしきい値は、ユーザーが調整できます。

ロード・バランシング・サポートをオンにするには、以下のオプションをエクスポートする必要があります。

export MALLOCOPTIONS=pool:0x80000000,pool_balanced
export MALLOCFREEPOOL=min_size<-max_size>:threshold_value<,min_size<-max_size>:
threshold_value, ... >,default:threshold
次の例では、0 から 16 バイト、256 チャンクのメモリーを提供するプールのしきい値が設定され、32 バイト・チャンクを処理するプールのしきい値が 512 バイト・チャンクに設定されます。残りのプールでは、128 バイト・チャンクがしきい値です。
export MALLOCFREEPOOL=0-16:256,32:512,default:128

デバッグ・サポート

このハイパフォーマンスのフロントエンドのデバッグ・バージョンはありません。 MALLOCDEBUG 環境変数が設定されている場合、プール・オプションは無視されます。 アプリケーションは、プールを活動化する前に「通常」の malloc を使用してデバッグされます。

ユーザー定義の割り当てポリシーについて

malloc サブシステムは、ユーザーがそれを使用して、システム・ヒープの管理とメモリーの割り当てを行うユーザー独自のアルゴリズムを開発できるメカニズムを提供します。

no_overwrite オプションについて

no_overwrite は、すべての割り当てポリシーで使用可能な追加オプションです。 malloc サブシステム内の glink コードのオーバーヘッドを削減するために、malloc サブシステム API の関数ディスクリプターが実際の基礎部分のインプリメンテーションの関数ディスクリプターで上書きされます。 一部のプログラム (サード・パーティー作成のデバッガーなど) は、 関数ポインターがこの方法で変更されると機能しなくなる可能性があるので、no_overwrite オプションを使用してこの最適化を使用不可にすることもできます。

この最適化を使用不可にするには、プロセスを始動する前に MALLOCOPTIONS=no_overwrite を設定します。

各種の割り当てポリシーの比較

上記で詳しく解説したさまざまな malloc 割り当てポリシーは、個別にまたはサポートされる方法で結合して使用されるとき、アプリケーション開発者に柔軟性を提供します。 アプリケーション固有の要件を認識して、有益な方法で各種の割り当てポリシー・パラメーターを調整するのは、開発者の責任です。

デフォルト割り当てポリシーと malloc 3.1 割り当てポリシーの比較

malloc 3.1 割り当てポリシーは、各割り当て要求サイズを次の 2 のべき乗まで切り上げるため、 仮想メモリーおよび実メモリーに深刻なフラグメントが発生し、参照の効率が低下します。 一般には、デフォルト割り当てポリシーを選択したほうが望ましいといえます。 デフォルト割り当てポリシーは、要求された分だけスペースを割り当て、前に使われたメモリー・ブロック の再利用をより効率的に行うからです。

残念ながら、アプリケーション・プログラムのなかには、意図せずに、許容できるパフォーマンスや 正常な機能を、malloc 3.1 割り当てポリシーの副次作用に依存しているものがあります。 例えば、 プログラムが配列の終わりを超えてしまっても、malloc 3.1 アロケーターなら切り上げプロセスで作られた余分の スペースがあるので、正常に機能することがあります。 同じプログラムがデフォルトのアロケーターを使うと、振る舞いが不安定になったり、異常終了したりすることが 考えられます。デフォルトのアロケーターは要求されたバイト数だけしか割り当てないためです。

もう 1 つの例として、malloc 3.1 割り当てアルゴリズムのスペース再利用が非効率なため、 アプリケーション・プログラムは、ほぼ毎回ゼロにセットされたスペースを受け取ることがあげられます (プロセスが作業セグメントのなかの指定されたページを最初に処理するとき、そのページはゼロにセットされる)。 この副次作用がないと、アプリケーションが正常に実行されない場合もあります。 実際には、 割り当てられたスペースをゼロで埋めるのは malloc サブルーチンの機能の仕様ではなく、 結果的に、必要なときだけおそらくゼロ以外で初期化するプログラムに対しては、不必要なパフォーマンス上の負荷を もたらすこともあり得ます。 デフォルトのアロケーターはスペースをより積極的に再利用 しているため、プログラムが malloc からゼロ埋めされたスペースを受け取ることに 依存していると、デフォルトのアロケーターを使用したときに異常終了してしまうことがあります。

同様に、プログラムが絶えず構造体を少しずつ大きなサイズに 再割り当てしている場合、malloc 3.1 アロケーターは構造体を頻繁に移動しなくてもよい場合があります。 多くの場合、realloc サブルーチンは、malloc 3.1 割り当てアルゴリズムにより暗黙に丸められた余分なスペースを利用できます。 通常、デフォルトのアロケーターは構造体をわずかに大きなエリアに移動する必要があります。 その上の部分に malloc サブルーチンによって別のものが呼び出されている可能性があるためです。 このため、malloc 3.1 アロケーターの代わりにデフォルトのアロケーターを使うと、realloc サブルーチンのパフォーマンスが低下してしまう場合もあります。 実際には、これはアプリケーション・プログラムの 構造の中に暗黙的にあるマイナス面が表面化したものと考えることができます。

アプリケーションのシステム・ヒープ管理エラーのデバッグ

malloc サブシステムは、アプリケーション開発者がプログラムのヒープ管理のエラーを デバッグして修正するのに役立つデバッグ・ツールのコレクションを提供します。 これらのデバッグ・ツールは、MALLOCDEBUG 環境変数を介して制御されます。

malloc 環境変数とオプションの概要

以下の表は、MALLOCTYPE 環境変数と MALLOCOPTIONS 環境変数の間の互換性を示したものです。
表 1. MALLOCTYPEMALLOCOPTIONS 環境変数の間の互換性
  マルチヒープ (およびサブオプション) バケット (およびサブオプション) スレッド・キャッシュ 特記 no_overwrite
デフォルト・アロケーター あり あり あり あり あり
3.1 なし なし あり あり あり
Watson なし なし なし なし なし
Watson2 なし なし なし なし なし
ユーザー: なし なし なし なし あり
表 2. MALLOCDEBUGMALLOCTYPE 環境変数の間の互換性
  York Town<デフォルト・アロケーター> 3.1 Watson Watson2 ユーザー:
catch_overflow (およびサブオプション) あり なし あり あり なし
report_allocations あり なし あり あり なし
postfree_checking あり なし あり あり なし
validate_ptrs あり なし あり あり なし
trace あり なし あり あり なし
log あり なし あり あり なし
verbose なし なし なし なし なし
すべての MALLOCDEBUG オプションは互換性があり、MALLOCOPTIONS でサポートされます。

Watson2 割り当てポリシーについて

Watson2 の malloc サブシステムは、アプリケーションが単一スレッドから複数スレッド (あるいはその逆) に変更されたとき、そのアプリケーションの振る舞いに適応します。このサブシステムは、プログラムの振る舞いによって数が変動するヒープ構造を使用するスレッド固有のメカニズムを使用します。従って、構成オプションは何も必要ありません。Watson2 の malloc サブシステムは、多数のワークロードに対して操作当たりのコストをならし計算して O に低減しています (logN 構成の場合)。これは、膨大な数の操作を一定の時間に同期なしで実行することができるからです。

割り当て

割り当ては複数のメカニズムを組み合わせて処理されます。これらのメカニズムは、アクティブなスレッドの数、要求のサイズ、およびプロセスの割り当て解除の履歴などのパラメーターによって決まります。割り当てに使用されるメカニズムのセットはスレッド固有のキャッシュから取り出され、さまざまな数のヒープ構造を使用します。これらのヒープ構造は、2 つの red-black ツリーとページ・ベースの合体に対するスレッドの親和性を持っています。

割り当て解除

割り当て解除は、割り当ての場合の振る舞いと同じパラメーターに基づきます。通常、戻されるブロックはスレッド固有のキャッシュに収集されます。メモリーは、ヒープの親和性と容量の使用状況に基づいて、複数のヒープ構造のいずれかに戻されます。場合によっては、複数のヒープ構造のコンテンツが共通のヒープ構造に統合され、合体効率が向上し、ヒープのフラグメント化が削減されます。アプリケーション・エラーに対する頑強性を向上するために、 アロケーターは、無効なポインターや破損したブロックの割り当て解除をある程度まで識別し、これらの操作をフィルターに掛けます。

再割り当て

十分な大容量ブロックのメモリーが再使用されます。現行ブロックでは要求を満たすことができない場合、通常の割り当て解除と割り当てにより置き換えられます。

制限

Watson2 の malloc サブシステムは、アプリケーションに適応でき、他のオプションは何も必要ありません。ただし、Watson2 の malloc サブシステムは、MALLOCDEBUG 変数が制御するデバッグ機能 validate_ptrsreport_allocations、および trace をサポートします。割り当てに関連するレポートは、output:<filename> オプションを使用してファイルに転送できます。MALLOCDEBUG 変数について詳しくは、malloc デバッグ・ツールを参照してください。