7

メモリに制約のあるマイクロコントローラ用に、Cでヒープ割り当てアルゴリズムを実装しようとしています。私は自分が知っている2つのオプションに検索を絞り込みましたが、私は提案を非常に受け入れており、これに経験のある人からのアドバイスやコメントを探しています。

私の要件:

-速度は間違いなく重要ですが、二次的な懸念事項です。

-タイミングの決定論は重要ではありません-決定論的な最悪の場合のタイミングを必要とするコードのどの部分にも、独自の割り当て方法があります。

-主な要件はフラグメンテーション耐性です。デバイスはluaスクリプトエンジンを実行しています。これには、さまざまな割り当てサイズ(32バイトブロックで重い)が必要です。主な要件は、このデバイスがヒープを使用不可能な状態に変えることなく長時間実行されることです。

また注意:

-参考までに、128Kから16MBの範囲のメモリまたはメモリ(下端に焦点を当てた)を備えたCortex-MおよびPIC32パーツについて説明しています。

-コンパイラのヒープを使用したくないのは、1)すべてのコンパイラで一貫したパフォーマンスが必要であり、2)それらの実装は一般に非常に単純であり、断片化に関しては同じかそれより悪いためです。

-私が資金的に変更して再検証したくない巨大なLuaコードベースのために、二重の間接オプションが出ています。

これまでの私のお気に入りのアプローチ:

1)バイナリバディアロケータを用意し、メモリ使用効率を犠牲にします(2の累乗に切り上げます)。-これは(私が理解しているように)再チェーンのための高速バディブロックルックアップのためにメモリアドレスでソートされた空きノードを格納するために各注文/ビンのバイナリツリーを必要とします。

2)空きブロック用に2つのバイナリツリーを用意します。1つはサイズで並べ替え、もう1つはメモリアドレスで並べ替えます。(すべての二分木リンクはブロック自体に格納されます)-割り当ては、サイズによるテーブルのルックアップを使用して最適であり、アドレスによって他のツリーからそのブロックを削除します-割り当て解除は、再チェーンのためにアドレスによって隣接するブロックをルックアップします

-どちらのアルゴリズムでも、割り当てられたブロックの開始前に割り当てサイズを保存する必要があり、ブロックは2から4の累乗(または配置によっては8)で出力されます。(メモリアドレスでソートされた割り当てを追跡するためにバイナリツリーを他の場所に保存しない限り、これは適切なオプションとは見なされません)

-どちらのアルゴリズムにも、高さのバランスが取れたバイナリツリーコードが必要です。

-アルゴリズム2には、2の累乗に切り上げてメモリを浪費する必要はありません。

-どちらの場合でも、ネストされたビットフィールドによって割り当てられた32バイトブロックの固定バンクを使用して、このサイズ以下のブロックをオフロードします。これにより、外部の断片化の影響を受けなくなります。

私の質問:

-アプローチ1がアプローチ2よりも断片化の影響を受けにくい理由はありますか?

-要件に合う可能性のある、私が見逃している代替案はありますか?

4

2 に答える 2

1

ブロックサイズが2の累乗または同等の値(*)に切り上げられない場合、特定の時点で存在する非永続的な小さなオブジェクトの数が限定。もちろん、バイナリバディアロケータはその特定の問題を回避します。そうでなければ、限られた数の適切に関連するオブジェクトサイズを使用しているが、「バイナリバディ」システムを使用していない場合でも、新しいブロックを割り当てる場所を決定する際に何らかの判断を行う必要があります。

考慮すべきもう1つのアプローチは、永続的、一時的、または半永続的であると予想されるものに異なる割り当て方法を使用することです。断片化は、一時的および永続的なものがヒープ上でインターリーブされるときに最も問題を引き起こすことがよくあります。このようなインターリーブを回避すると、断片化を最小限に抑えることができます。

最後に、二重間接ポインタを実際に使用したくないことはわかっていますが、オブジェクトの再配置を許可すると、断片化に関連する問題を大幅に減らすことができます。Microsoftから派生した多くのマイクロコンピュータBASICは、ガベージコレクションされた文字列ヒープを使用していました。Microsoftのガベージコレクターは本当にひどいものでしたが、その文字列ヒープアプローチは優れたアプローチで使用できます。

于 2012-05-29T19:29:36.587 に答える
1

http://www.mcdowella.demon.co.uk/buddy.htmlで(実際には使用されていない) Buddy システム アロケーターを入手できます。しかし、メモリアロケータを差し込むだけで簡単に解決できる問題があるとは思いません。私がよく知っている長期稼働の高整合性システムでは、予測可能なリソース使用量があり、リソースごとに 30 ページ以上のドキュメントで説明されています (主に CPU と I/O バス帯域幅 - メモリは起動時に毎回同じ量を割り当てる傾向があるため簡単です)そして二度とありません)。

あなたの場合、静的な割り当て、空きリスト、スタック上の割り当てなどの通常のトリックはどれも機能していないことが示されています。実行時 - 使い果たされるまでメモリを割り当てるループに入るとどうなりますか?

メモリの使用を 2 つのセクションに分けることができますか? 従来のコードは、起動時に必要なもののほとんどすべてを割り当て、二度と割り当てません。消耗コード (Lua など) は、必要なときに必要なものを割り当て、後に残ったものから割り当てます。静的割り当て?従来のコードを気にせずに、メモリのすべての領域を使用するか、断片化することができた場合、消耗コードの再起動または何らかのクリーンアップをトリガーできますか?

于 2012-05-30T05:38:14.680 に答える