• ベストアンサー

仮想メモリでない環境でのmalloc freeのよいアルゴリズムを教えてください

ゲーム機の開発をしています。 仮想メモリがないので、mallocとfreeを不定の順序で繰り返しているとヒープ領域が断片化し、そのうちにメモリは不足していないはずなのにmallocできなくなります。ゲーム機のSDKにはそういうことを想定しているのか malloc、free の代替関数を設定できるようになっています。そこで、代替関数を用意しようと考えていると考えています。 完全に断片化をさけるには、mallocした逆順にfreeするとか使い方の工夫をしないと無理とは思いますが、通信系のライブラリにの内部などでmallocしていたりして完全にはこちらの思うとおりにはできません。テクスチャーなどの常駐でなるべく多くのメモリを使いたいので、ヒープ領域はできるだけ小さくすませたいのです。どんなアルゴリズムでも、ある程度の断片化はさけられないと思いますが、malloc、freeのよいアルゴリズムが紹介されているところがありましたら、御教えください。使われ方との相性があると思いますので、複数のアルゴリズムが紹介されていればうれしいです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

> 代替関数を用意しようと考えていると考えています。  そうですね。メモリ管理は完全に乗っ取ってしまった方がいいでしょう。 > 完全に断片化をさけるには、mallocした逆順にfreeするとか使い方の工夫をしないと無理とは思います  仰るとおり使う側で工夫するのが一番効率がいいです。  例えば、使用用途毎にメモリブロックを分けてしまうというと管理は楽になるのではないでしょうか。  その通信のライブラリが malloc/freeを直接呼んでしまうというのであれば、ゲーム起動時にそのライブラリが使用するだろうメモリサイズを除いてごっそり確保してしまい、ユーザは自前のルーチンからメモリを取得するようにすれば、通信ライブラリによる断片化は避けれられます。 > malloc、freeのよいアルゴリズムが紹介されているところがありましたら、御教えください http://www.ylw.mmtr.or.jp/~trustno1/legos/legos_4.html  このページで簡単な説明をしているのを見つけました。  ただ個人的にはメモリ管理のアルゴリズムは、アロケート数が多くなると空きブロックの検索にそれだけ時間がかかるようになるのでシンプルなのが一番いいような気がします。

moritan2
質問者

お礼

お礼ですが、シミュレーションの結果をレポートしておきます。 URLの記述とは違い、ベストフィットの方がよいという結論でした。 同一の seed値を使い、ランダムに確保、開放を繰り返して、確保に失敗するまでのループの回数を数えたのですが、ベストフィットの方が確保の失敗までのループ回数が多かったです。

moritan2
質問者

補足

URL読ませていただきました。 質問をする前にいくつか自作してテストしていたのですが、普通に思いついたのはこのベストフィットと同じ方法でした。それが、ファーストフィットの方がよいとは驚きでした。やっぱり、質問してみるもんですね。たすかりました。自分なりに、ここにあるアルゴリズムでシミュレーション、テストしてみます。

その他の回答 (3)

  • chirubou
  • ベストアンサー率37% (189/502)
回答No.4

malloc/free のアルゴリズムは、もし、サイズに特長があって、それが事前に分かっているのなら可能ですが、これをやるには結構手間がかかります。 私だったら、小さいサイズの malloc はいくつかまとめて malloc し、free_list でつないで自分で管理するような my_malloc を作ります。 my_malloc では free_list が空の場合は新たに複数の領域をまとめて malloc し、それぞれを free_list に登録後、最初のひとつを返し、空でない場合は free_list からひとつ取り出します。my_free では領域を free_list につなぎます。 これはサイズが固定の場合ですが、可変の場合は、例えば、大、中、小、それぞれの free_list を持つ、というやり方も考えられます。特大(もしあれば)は malloc をそのまま呼んでしまえばいいでしょう。この場合 my_free に長さ指定を省略したい場合は、malloc 同様、my_malloc が返すアドレスの前に長さを入れておく等の小技が必要になり少し面倒になります。 この方が普通に malloc を呼ぶより速いし、小さい領域の malloc がなくなるので断片化を押さえることができます。

moritan2
質問者

補足

今回の私の状況が説明不足でしたので説明いたします。 まず、いままで私はゲーム機でのプログラミングの場合は標準のmallocはいっさい使っておりません。経験的にMMUが搭載されていないマシンでのmallocはそのうちメモリの断片化のためにひどいことになることがわかっているからです。そのため、起動直後にmallocではなくheapからメモリを確保する関数でスタックに必要な分を残して全メモリを確保しています。この領域の先頭をheap_topに入れておいて、メモリを確保する場合はheap_topを返し、heap_top += size します。free する場合は、heap_topを元に戻すだけという方法です。非常に単純なので、問題はめったに起きません。ただし、こういうやりかたをしている場合は基本的に標準のmallocとの併用は不可能です。ところが、通信ライブラリがmallocを使うのでmallocが必要になりました。救いはmallocが置き換え可能であるということです。そのため、他のテクスチャー領域などと同じようにmalloc領域を確保し、自前のmallocでそれを使うことにしました。したがって、mallocを使うのは私ではなく通信ライブラリのみなのでどんな確保のされ方をするのか事前にはわかりません。ただ、自分のmallocに使用状況をダンプするデバッグ用関数を用意して、だいたいのことは分かるかもしれません。 free_listをサイズごとにわけるというのはいいアイデアですね。free_listのサーチの時間が減りますね。

  • rinkun
  • ベストアンサー率44% (706/1571)
回答No.3

断片化しないmallocは不可能ではないですよ。メモリ利用効率は悪いですけど。 基本は固定長メモリブロックを使うことです。たとえば一回のmallocで要求する最大サイズが4KBだとしたら、メモリを4KB単位のブロックで扱い何バイトの要求でも必ず4KBのブロックを返すようにします。これならmalloc順序による断片化はしません。無駄は多いですけど。 まあこれではあんまりなので、固定長メモリブロックをサイズごとに幾つか用意します。8バイト、32バイト、128バイト、1KB、4KBとか。各サイズのブロックをいくつ用意するかはシステムでの使用状況に合せて設定します。 そしてmallocでは要求サイズ以上のサイズの空きブロックを探して返します。上記例では4バイト要求されても8バイト要求されても8バイトのブロックを返し、10バイトの要求があれば32バイトのブロックを返します。 # 例では2冪サイズで書きましたが、特定サイズの要求が多いことが分かっていればそのサイズの固定長メモリブロックを用意する方が効率的です

moritan2
質問者

補足

断片化はしませんが、サイズが一致しない分は結局むだになってしまいますよね。今回の一番重要な課題はメモリの使用効率のアップなので、今回は目的に合わないようです。しかし、同じような大きさの小さな領域を大量に確保するような用途では、このアルゴリズムはサーチする必要が無いので非常に強力ですね。

  • Qwerty-36
  • ベストアンサー率25% (58/226)
回答No.1

ともかく、組み込み系の人間なので、mallocは大嫌い(^^;)です。 >ゲーム機のSDKにはそういうことを想定しているのか malloc、free の代替関数を設定できるようになっています。   ↓ ゲーム機(embedded)の場合、メモリマップは固定ですから、あまりmalloc、freeのお世話にならない様にします。どうしても必要な場合は、そのボードのメモリマップに合わせて自分の責任でmalloc、freeを実装します。 ということで、mallocを使わない様にアルゴリズムを見直すことが肝要かと思います。どうしても使わなければいけないのであれば、一定の時間ごとにgarbage collectionを行うのが良いかと思います。 通信ライブラリの中で、最大、どの程度のバッファ領域をmallocし消費するか、見積もって、そこをメモリマップの一番端に持ってくる様にしてください。(最悪は、その通信ライブラリの使用を見直さないといけないですね。)

moritan2
質問者

補足

私もmallocは大嫌いです。仮想記憶の無いシステムでmallocがまともに動くとはとても思えません。ですから、いままではゲームの開始直後にスタックに必要な分を除いて全ヒープメモリを確保してこちらの管理下でメモリを使うようにしていました。ところが、通信ライブラリが malloc を使うために今回どうしてもmallocを使わなくてはいけなくなりました。ライブラリは認証などが含まれているので、使わないわけには行きません。救いは、mallocが置き換え可能なので、最適なアルゴリズムとheap領域とサイズが指定できることです。それでこの質問をしております。 なお、ガベージコレクションは無理と思います。ライブラリに確保したポインタが変化したことを伝えることができないからです。これも仮想記憶が無いことによる問題ですね。

関連するQ&A

  • malloc でのメモリ取得状況の可視化

    Cで作成したWinXPで動くプログラムです。 malloc - free を繰り返して使っていると、どうもメモリが断片化するらしく、よくメモリ不足でエラーになります。free で開放したつもりで、開放できていないという可能性も否定できません。 そこで、メモリ確保状態を可視化できるツールなどありましたら紹介お願いします。 アプリのソースリストがありますので、可視化するプログラムを埋め込むことも可能です。そのようなライブラリのご紹介も歓迎です。 よろしくお願いいたします。

  • メモリ操作関数『malloc(),free()』

    /*10バイトのメモリ領域を確保し、その領域に文字列"Allocate"を代入せよ。*/ /*ただし、確保した領域は、プログラム終了までに開放すること。*/ #include<stdio.h> #include<stdlib.h> void main(void) { char *ptr; ptr = (char *)malloc(10); printf("Allocate\n"); free(ptr); } 今、ライブラリ関数を勉強しています。 この問題をとりあえず作ってみて、実行も成功したのですが、10バイトのメモリ確保の数値を変えても、何も変わらないため本当に問題の要求どおりのプログラムが作れているのか謎です。 間違っているなどのアドバイス宜しくお願いします。

  • 仮想メモリ増加

    WindowsでJavaWebStartのアプリケーションを起動しています。 10日程起動したままにしておくとタスクマネージャのjavaw.exeの仮想プロセスが増加し続けています。 起動時は200M程度で10日後は1Gを超えています。 メモリリークかと考え調べましたがヒープ領域も非ヒープ領域も増えていません。 メモリの断片化かと考え仮想メモリ増加後にメモリクリーナも試しましたが、メモリは減少しません。 microsoftのvadumpも使い調べましたが、問題あるように見えません。 やはり、プログラムの問題でしょうか?それかjavaのコンパイラの問題でしょうか? どなたかご教授願います。 調査の手段だけでもいいです。

  • malloc関数 free開放とはなんですか?

    malloc関数を用いてメモリを確保した後、 必ずfreeで開放を行わなければならないですよね? この開放とはどういう意味なのでしょうか?

  • malloc関数によるメモリの確保

    C初心者です。 malloc関数によるメモリの確保に関して教えてください。 2次元配列のサイズに対してmalloc関数の引数値をたとえば、 (double*)malloc(datasize*sizeof(double)) などとしメモリ領域を確保すると、メモリアドレスはデータのサイズ によらず一定 1234044、1234048となります。 データサイズを大きくし、datasize*sizeof(double)が16Kバイトを超えるとcmd.exeがエラーとなり落ちます。 デバックモードで実行すると 「"System.AccessViolationException"のハンドルされていない例外が不明なモジュールです。で発生しました。 追加情報:保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリがこわれていることが考えられます」 というメッセージがでます。 コンパイラはExpressEdition2008です。 この現象を回避するにはどうすべきか、なぜこのようなことが起こるのかご教授ください。 よろしくお願いいたします。

  • C/C++言語のメモリについて

    C言語でメモリを2種類?に分けると、スタックとヒープがあります。 ヒープは mallocなどで確保し、freeで解放しますがスタックは解放する必要がありません。 そのスタックは通常、何バイトまで可能なのでしょうか? あと関数外のファイルの先頭に int[1000000];とした場合、このメモリはmallocで確保していませんが、 どこに作られるのでしょうか? 私のパソコンはメモリが2GBでWindows2000ですが、CやC++で最大、何バイトまでメモリが使えますか? また、一番多くメモリを確保できるなら、OSはなんでも構いません。 解釈等も間違っていたらご指摘していただきたいです。

  • mallocによる確保外の領域への参照

    構造体をmallocにより動的確保を行っていたのですが、例えば typedef struct _point{ int x, y; } point; point *pelem_point; pelem_point = (point *)malloc(sizeof(point)*5); このように、point型の構造体を5つ確保するとします。 しかし、 (pelem_point+100)->x = 1; (pelem_point+100)->y = 2; printf("%d\n", (pelem_point+100)->x); printf("%d\n", (pelem_point+100)->y); とやったら、確保していない100個先のところも構造体として利用できました。 なぜなのでしょうか。 自分の考えではこのようになりました。 mallocによりヒープ領域から適当な空いているメモリのアドレスが渡されるため、そこからはヒープ領域より先に、限りがあるまで進めてしまうために確保外のサイズにアクセスしても使えてしまっている。 また、mallocにより確保した場合は使用中のラベルがはられるため他に侵されることはないが、先の例のようにmallocによって確保してない場合はいくら使用できたとしても、空いているとコンピュータでは認識されるため、何かヒープ領域を使う場合に勝手に上書きされてしまう可能性がある。 しかし、この考えでも、なぜ確保外の領域が構造体のサイズ分ずつ区切られているのか納得いきません。 わかる方いましたらよろしくお願いします。

  • c言語のmalloc関数、またrealloc関数

    c言語のmalloc関数は確保するメモリの領域を、配列としてのみしか処理出来ないのですか。 つまり、malloc関数で確保したメモリの領域を変数、また多次元配列、また構造体としては処理出来ないのでしょうか。 c言語のrealloc関数は以前の確保したメモリの領域から、確保し直したメモリの領域の場所が変わるかもしれないという事ですが、この場合の場所が変わるという意味は、メモリの領域のアドレスが変わるという事でしょうか。 また、以前の確保したメモリの領域に代入していたデータが使用出来なくなるという事でしょうか。

  • malloc関数の使い終わった後の開放について

    今、Cでmalloc関数を使った簡単なプログラムを作っています。 それを作っているときに思ったのですが、mallocを使って出来た領域を、freeで開放する前に異常終了したとします。 そういったときに開放する方法はないのでしょうか? 学校の先生から聞いた話によると、「パソコンを次に立ち上げたときに開放される」みたいなことを聞いたのでやらなくてもいいのかも知れませんが、気になるので教えてください。

  • メモリをたくさん使うテストプログラム

    Linuxで、メモリをたくさん使うようなテストプログラムを作りたいのです。 メモリといっても、プログラムコードの入っているテキスト領域、データの入っているデータ領域、ヒープ領域などがあると思いますが、 これらのいずれかのみをたくさん使うようなプログラムを作りたいのです。 例えば、サイズの大きなプログラムであれば、テキスト領域が大きくなったり、 大容量の文字列を扱ったりすると、データ領域が大きくなったりするんでしょうか? 関数とメモリ使用量の関係があまり分かっていません。 どうか教えてください。