組み込みシステム用のソフトウェアを開発している間、私はrealloc()
何度も関数を使用しました。今、私はrealloc()
何の説明もなく「組み込みで使用すべきではない」と言われています。
realloc()
組み込みシステムにとって危険であり、その理由は何ですか?
組み込みシステム用のソフトウェアを開発している間、私はrealloc()
何度も関数を使用しました。今、私はrealloc()
何の説明もなく「組み込みで使用すべきではない」と言われています。
realloc()
組み込みシステムにとって危険であり、その理由は何ですか?
はい、すべての動的メモリ割り当ては危険であると見なされ、産業/自動車/航空宇宙/医療技術などのほとんどの「高整合性」組み込みシステムから禁止されています。質問に対する答えは、組み込みシステムの種類によって異なります。あなたがやっている。
高整合性の組み込みシステムから禁止されている理由は、潜在的なメモリリークだけでなく、これらの関数に関連する多くの危険な未定義/未指定/impl.definedの動作です。
編集:私はまた、別の危険であるヒープの断片化について言及するのを忘れました。さらに、MISRA-Cは、使用すべきでない理由として「データの不整合、メモリの枯渇、非決定論的な動作」についても言及しています。前の2つはかなり主観的なように見えますが、非決定論的な動作は、この種のシステムでは絶対に許可されていないものです。
参照:
特定の組み込みシステムによって異なります。小さな組み込みシステムでの動的メモリ管理は、最初は注意が必要ですが、とrealloc
よりも複雑ではありません(もちろん、それはそれが行うことではありません)。一部の組み込みシステムでは、そもそも呼び出すことを夢見たことはありません。他の組み込みシステムでは、ほとんどデスクトップのふりをします。free
malloc
malloc
組み込みシステムのアロケータが不十分であるか、RAMが少ない場合は、realloc
断片化の問題が発生する可能性があります。それがあなたも避ける理由ですmalloc
、それが同じ問題を引き起こすからです。
もう1つの理由は、一部の組み込みシステムは信頼性が高くなければならず、malloc
/realloc
が戻る可能性があることNULL
です。このような状況では、すべてのメモリが静的に割り当てられます。
多くの組み込みシステムでは、カスタムメモリマネージャーはmalloc / realloc/freeで利用できるよりも優れたセマンティクスを提供できます。たとえば、一部のアプリケーションは、単純なマークアンドリリースアロケータでうまくいくことができます。まだ割り当てられていないメモリの先頭へのポインタを保持し、ポインタを上に移動して割り当て、下にポインタを移動して投棄します。後に割り当てられた他のものを保持しながらいくつかのものを投棄する必要がある場合、それは機能しませんが、それが必要でない状況では、マークアンドリリースアロケータは他の割り当て方法よりも安価です。マークアンドリリースアロケータが十分でない場合は、ヒープの最初からいくつかのものを割り当て、ヒープの最後から他のものを割り当てることが役立つ場合があります。
非マルチタスクまたは協調マルチタスクシステムで役立つ場合がある別のアプローチは、直接ポインタではなくメモリハンドルを使用することです。典型的なハンドルベースのシステムでは、割り当てられたすべてのオブジェクトのテーブルがあり、メモリの上部に下向きに構築され、オブジェクト自体は下から上に割り当てられます。メモリ内の割り当てられた各オブジェクトは、それを参照するテーブルスロットへの参照(ライブの場合)またはそのサイズの表示(デッドの場合)のいずれかを保持します。各オブジェクトのテーブルエントリは、オブジェクトのサイズとメモリ内のオブジェクトへのポインタを保持します。オブジェクトは、空きテーブルスロットを見つけるだけで割り当てられ(テーブルスロットはすべて固定サイズであるため簡単です)、空きメモリの開始時にオブジェクトのテーブルスロットのアドレスを保存し、それを超えてオブジェクト自体を保存します。空きメモリの開始を更新して、オブジェクトのすぐ先を指すようにします。後方参照を長さ表示に置き換え、テーブル内のオブジェクトを解放することにより、オブジェクトを解放できます。割り当てが失敗した場合は、メモリの先頭からすべてのライブオブジェクトを再配置し、デッドオブジェクトを上書きし、オブジェクトテーブルを更新して新しいアドレスを指すようにします。
このアプローチのパフォーマンスは非決定論的ですが、断片化は問題ではありません。さらに、一部の協調マルチタスクシステムでは、「バックグラウンドで」ガベージコレクションを実行できる場合があります。ガベージコレクターがスラックスペースを通過するのにかかる時間でパスを完了することができれば、長時間の待機を回避できます。さらに、いくつかのかなり単純な「世代別」ロジックを使用して、最悪の場合のパフォーマンスを犠牲にして平均的な場合のパフォーマンスを向上させることができます。
realloc
できるように失敗する可能性がありmalloc
ます。これが、組み込みシステムでもおそらく使用すべきではない理由の1つです。
realloc
malloc
の間に古いポインタと新しいポインタを有効にする必要があるという点よりも悪いですrealloc
。つまり、元のメモリスペースの2倍malloc
に加えて、追加の量が必要になります(realloc
バッファサイズが増加していると想定)。
使用realloc
すると、メモリ位置への新しいポインタが返される可能性があるため、非常に危険です。これの意味は:
realloc
。realloc
はアトミックである必要があります。これを実現するために割り込みを無効にしている場合realloc
、ウォッチドッグによってハードウェアがリセットされるのに十分な時間がかかる可能性があります。更新:私はそれを明確にしたかっただけです。/を使用してrealloc
実装するよりも悪いと言っているのではありません。それも同じくらい悪いでしょう。サイズを変更せずにシングルを実行できる場合は、少し良くなりますが、それでも危険です。realloc
malloc
free
malloc
free
組み込みシステムでのrealloc()の問題は、他のシステムと同じですが、メモリがより制約され、障害の息子シーケンスが受け入れられないシステムでは、結果はより深刻になる可能性があります。
これまで言及されていない問題の1つは、realloc()(およびその他の動的メモリ操作)が非決定論的であるということです。つまり、実行時間は変動し、予測できません。多くの組み込みシステムもリアルタイムシステムであり、そのようなシステムでは、非決定論的な動作は受け入れられません。
もう1つの問題は、スレッドセーフの問題です。ライブラリのドキュメントをチェックして、ライブラリが動的メモリ割り当てに対してスレッドセーフであるかどうかを確認します。通常、そうである場合は、ミューテックススタブを実装して、特定のスレッドライブラリまたはRTOSと統合する必要があります。
すべてのemebddedシステムが似ているわけではありません。組み込みシステムがリアルタイムではない場合(または問題のプロセス/タスク/スレッドがリアルタイムではなく、リアルタイム要素から独立している場合)、大量の未使用のメモリ、または仮想メモリ機能がある場合、その場合、ほとんどの場合、おそらく不適切なアドバイスであれば、realloc()の使用は許容される可能性があります。
「従来の知識」を受け入れて動的メモリを禁止するのではなく、システム要件と動的メモリ機能の動作を理解し、適切な決定を行う必要があります。とは言うものの、可能な限り幅広いプラットフォームやアプリケーションへの再利用性と移植性のためのコードを構築している場合、再割り当てはおそらく本当に悪い考えです。たとえば、ライブラリに隠さないでください。
コンテナの容量が増加したときにデータを動的に再割り当ておよびコピーするC++STLコンテナクラスにも同じ問題が存在することにも注意してください。
この操作は特にループに入れるのにコストがかかるため、可能であればreallocの使用を避けることをお勧めします。たとえば、割り当てられたメモリを拡張する必要があり、現在のブロックと次の割り当てられたブロックの間にギャップがない場合-これ操作はほぼ同じです:malloc +memcopy+無料。