Next: , Previous: , Up: Top   [Index]


13 メモリ割り当て機能のカスタム化

GMPのデフォルトのメモリ割り当て関数はmalloc, reallocfreeです。これらがエラーを吐いた時には,標準エラー出力にメッセージを流し,プログラムを終了します。

デフォルトメモリ割り当て関数とは違うやり方でメモリ確保を行ったり,メモリが足りなくなった時の挙動を変えたりするために,他の関数を指定することも可能になっています。

Function: void mp_set_memory_functions (
void *(*alloc_func_ptr) (size_t),
void *(*realloc_func_ptr) (void *, size_t, size_t),
void (*free_func_ptr) (void *, size_t))

現在のメモリ割り当て関数群を引数に指定したものに置き換える。引数がNULLであれば,対応する関数はデフォルトのものがそのまま使用される。

ここで指定されたメモリ割り当て関数群は,GMPのあらゆるところで使用されることになります。但し,一時記憶領域は,GMPビルド時に指定があり,利用可能である場合は,alloca関数で確保されます。

mp_set_memory_functions関数は,指定前のメモリ割り当て関数で指定された使用中のGMPオブジェクトが存在しない場合にのみ,呼び出すようにして下さい。つまり,全ての他のGMP関数が実行される前に呼び出す必要がある,ということです。

こうして指定されたメモリ割り当て関数群は,下記のような型宣言をしておく必要があります。

Function: void * allocate_function (size_t alloc_size)

新規に確保されたalloc_sizeバイトのメモリ空間へのポインタを返します。

Function: void * reallocate_function (void *ptr, size_t old_size, size_t new_size)

確保済みのold_sizeバイトのメモリブロックptrnew_sizeバイトにリサイズします。

このメモリブロックは,必要があれば移動することもあります。例えば,old_sizeよりnew_sizeが小さい場合,新規に割り当てられたメモリ領域にnew_sizeバイト分コピーして移動しなくてはなりません。返り値はリサイズ後のメモリブロックへのポインタで,移動していれば新規のメモリブロック,移動していなければptrがそのまま引き継がれます。

ptrNULLになることはなく,常にここには既存のメモリブロックへのポインタが記憶されています。 new_sizeold_sizeより大きくても小さくても大丈夫です。

Function: void free_function (void *ptr, size_t size)

ポインタptrに確保されたメモリ空間を解放します。

ptrNULLになることはなく,常に確保済みのsizeバイト分のメモリエリアへのポインタが入ります。

ここでいうbyteとは,sizeofオペレータが使用するメモリ単位を意味します。

reallocate_function関数のold_sizeパラメータとfree_function関数のsizeパラメータは省力化のために渡されていますが,当然実装上必要でなければ無視されます。デフォルトのメモリ割り当て関数であるmalloc等が使用される時には不要なものです。

上記の関数群はエラーを返すことはありませんので,問題があった時には相応の処理を行う必要があります。allocate_function関数やreallocate_function関数がNULLを返すことはありません。

致命的なエラーに対する挙動は差異があった方が好ましいわけで,例えば,stderrにデフォルト的に出力するよりは,グラフィカルなダイアログを出す,というようにしましょう。メモリエラー(out of memory)は割と良くあることです。

例えばメモリエラー(out of memory)から回復するメモリ割り当て関数は今のところ定義されていませんので,起きた時にはプログラムを停止すべきです。longjmp関数やC++の例外発生が起こった時の挙動は未定義です。この仕様は将来変更されるかもしれません。

GMPはメモリブロックを割り当てて,他のメモリブロックへのポインタを保持することがあります。手堅いガベージコレクションスキームを構築したいのであれば,このようにしないことが望ましいということになります。

デフォルトのGMPメモリ割り当て関数はmalloc関数とその周辺の標準関数で,プログラムが最初に実行するのがmp_set_memory_functions関数であれば,これらの関数がリンクされるべきです。これが問題というのであれば,GMPのソースを書き変える必要があります。


Function: void mp_get_memory_functions (
void *(**alloc_func_ptr) (size_t),
void *(**realloc_func_ptr) (void *, size_t, size_t),
void (**free_func_ptr) (void *, size_t))

現在のメモリ割り当て関数を取り出し,引数に指定されたポインタにその関数を格納します。引数がNULLポインタであれば,格納はしません。

現在のメモリ解放関数を知りたい時には次のようにします。

void (*freefunc) (void *, size_t);

mp_get_memory_functions (NULL, NULL, &freefunc);