PICでのmallocの使用


10

PICでどのように使用malloc()およびfree()機能できますか?stdlib.hヘッダーを確認しましたが、言及されていません。MCC18を使用しています。

誰かがそれらを使用する必要がありましたか?

ライブラリをWindows XPからPICに移植しているので、それらが必要です。移植ガイドによると

オペレーティングシステムの特定の機能をPICの機能に適合させる

しかし、malloc()free()関数を「変換」する方法がわかりません。


4
可能であれば、静的割り当てを使用してください。
Nick T

1
どうして?問題は、私がかなり巨大なライブラリの最下層(プラットフォーム固有のもの)を書いていることと、それらが何のために使用されているのかわからない多くの関数がこれを使用していることです。動的から静的へ
stef

11
4KB未満のRAMを搭載したPICマイクロコントローラーは、アプリケーションにとって間違っている可能性があります。PCでは、ポートを開始する前にPCライブラリのメモリ使用量を測定します。あなたはARM Cortex-M3のようなより強力なものでより良いかもしれません。経験則:移植するコードベースが大きすぎて理解できない場合、PICに適合しません。
Toby Jaffey、2010

Windowsドライバー(および一般的なアプリケーション)は基本的に「無制限のRAM」パラダイムで書かれています。物理RAMが使い果たされた場合、仮想メモリがスワップインされる可能性があるためです。 PIC18F87J11で利用できます。ドライバーが使用するメモリの量を測定することはできないと思います。
Adam Lawrence、

別の潜在的な問題:Win32 intは32ビットですが、MCC18コンパイラでは16ビットしかありません。注意しないと、奇妙なオーバーフローの問題が発生する可能性があります。
Adam Lawrence、

回答:


8

多くのアプリケーションでは、メモリを割り当てる必要がありますが、その後に割り当てられたものを保持しながら、何かを解放する必要はありません。そのようなシステムでは、必要なことは、リンカーを使用して、使用可能なすべてのRAMを使用する配列を定義し、その配列の先頭にポインターを設定してから、簡単なmalloc関数を使用することだけです。

char * next_alloc;
void * malloc(int size)
{
    char * this_alloc;
    this_alloc = next_alloc;
    if((END_OF_ALLOC_SPACE-this_alloc)<サイズ)
      -1を返します。
    next_alloc + =サイズ;
    this_allocを返します。
}
void free(void * ptr)
{
    if(ptr)
        next_alloc =(char *)ptr;
}

素晴らしくて簡単で、割り当てがいくつあっても合計オーバーヘッドは2バイトだけです。ブロックでfree()を呼び出すと、そのブロックとその後のすべての割り当てが解除されます。

少し複雑な割り当てパターンは、2つのポインターを使用して処理できます。1つはメモリの下から上に移動し、もう1つはメモリの上から下に移動します。ヒープ内のデータが同種であり、外部へのすべての参照がどこにあるかがわかっている場合は、コンパクト化されたガベージコレクタを使用することもできます。


可能性について完全に情報を得るには、electronics.stackexchange.com
questions / 7850 /…で

14

malloc()マイクロコントローラでは一般的に「悪いこと」と考えられています。ただし、どうしても必要な場合は、サードパーティのバージョンを見つける必要があります。

運が良ければ、移植するコードはメモリブロックの再利用に依存しない場合があります。この場合、RAMバッファーにポインターを返し、要求されたブロックサイズだけポインターを進める単純なアロケーターを作成できます。

PCライブラリをマイクロコントローラーに移植する前に、このアプローチを使用して成功しました。

以下では、でアロケータを設定し、でmy_malloc_init()メモリを割り当てますmy_malloc()my_free()依存関係を満たすためにありますが、実際には何もしません。もちろん、最終的にはスペースが足りなくなります。

これを機能させるには、コードのワーストケースのメモリ要件を測定し(可能な場合はPCでこれを行う)、それにHEAP_SIZE応じて設定する必要があります。ライブラリの動的メモリを必要とする部分に入る前に、を呼び出しますmy_malloc_init()。再利用する前に、まだ何も指していないことを確認してくださいheap

uint8_t heap[HEAP_SIZE];
uint8_t *heap_ptr;

void my_malloc_init(void)
{
    heap_ptr = heap;
}

void *my_malloc(size_t len)
{
    uint8_t *p = heap_ptr;
    heap_ptr += len;
    if (heap_ptr >= heap + HEAP_SIZE)
        return NULL;
    else
        return p;
}

void my_free(void)
{
    // do nothing
}

(注:現実の世界では、ポインターの配置、つまりheap_ptr2バイトまたは4バイトで切り上げることを考慮する必要があるかもしれません)

別のオプションはmalloc()FreeListのように、通常提供されるよりも単純な割り当て構造を使用することですが、これでは可変サイズのブロックを割り当てることができない場合があります。


3
mallocが組み込みで良いものと見なされるのはいつでしょうか。
Kellenjb 2010

1
他の人が言ったように、プログラムで動的割り当てを望まないことに私はまだ同意しますが、これはそれを行うための素晴らしい方法です。組み込み向けに設計されたサードパーティのmallocは、群を抜いて最良の選択です。セグメンテーションの回避は必須です。@jobyTaffeyよく書かれています。
Kortuk

1
@Kellenjbよく、それはまったく新しい質問です:-)
Toby Jaffey

1
my_freeはheap_ptrに渡された値を設定し、示されたアイテムとその後に割り当てられたすべてを効果的に解放することをお勧めします。当然のことながら、そのような使用を可能にするシーケンスで物事を割り当てる必要がありますが、そのようなパターンは珍しいことではありません。別の便利なバリエーションは、2つのペアのalloc / free関数を使用することです。1つはトップダウンを割り当て、もう1つはボトムアップを割り当てます。
スーパーキャット、2011年

13

これはほとんどあなたの質問への答えではありませんが、動的メモリ割り当ては通常、小さなRAM環境ではオペレーティングシステムが存在しない場合(たとえば、マイクロコントローラの世界では)、埋め込まれた環境で利用できるヒープスペースは通常数百バイトで測定...

mallocとfreeの実装は、本質的には「フリーセグメント」構造のリンクリストのメンテナンスであり、ご想像のとおり、フリーセグメントに関連付けられたメタデータは、通常利用可能なメモリの量と比較しても実体的ではありません。 "動的メモリプールを管理すると、使用可能なリソースのかなりの量が消費されます。


メタデータのオーバーヘッドが非常に小さい実装があります。割り当てられたブロックの場合、必要なのはそのサイズだけです。未使用のブロックの場合、リンクされたリストポインターは、非常に妥当な最小のブロックサイズでも、通常は無料で収まります。
モニカを

マイクロコントローラを使用する小さくて長時間実行されるシステムの問題は、通常、メタデータではなく、メモリの断片化に関するものです。さらに悪いことに、コードに小さな変更を加えると、以前は存在しなかったメモリの断片化が発生する可能性があるため、無邪気に見える変更を行うと、突然プログラムが「早すぎる」動作を停止する可能性があります。
モニカを

11

C18標準ライブラリがmallocとをサポートしているかどうかはわかりませんfreeが、マイクロチップアプリケーションノートAN914に、独自のライブラリを実装する方法が示されています。

いずれにせよ、トーマスや他のポスターは、非常に小さなRAMスペースでPICに動的メモリを使用することは危険を伴うことを示唆しています。本格的なOSが提供するより高度な仮想メモリマネージャーがないため、連続した領域が急速に不足し、割り当ての失敗やクラッシュにつながる可能性があります。さらに悪いことに、それは確定的ではない可能性があり、デバッグするのはおそらく困難です。

あなたがやっていることが実行時に本当に動的に決定され(ほとんどの組み込みのものではまれ)、2、3の非常に特別な場合にのみスペースを割り当てる必要がある場合、私はmallocそれfreeを受け入れ、受け入れられます。


ヒープの断片化とも呼ばれる、連続したスペースが不足することは、アドレススペースの大きさや仮想メモリがあるかどうかに完全に依存しない問題です。ヒープの断片化を少なくするために、いくつかの無駄なRAMをトレードオフしたい場合がありますが、最終的には、長時間実行されているシステムでは、ヒープ領域が不足しないという保証はありません。ここでの小さなシステムと大きなシステムの唯一の違いは、ディスクがスラッシングを開始するのにかかる時間(ディスクページのVMを備えたシステムの場合)、またはアロケーターがNULLを返すのに(埋め込まれたものの場合)です。
モニカを

@KubaOber:通常、特定のサイズのRAMが、特定の(より少ない)量以上のRAMを同時に割り当てる必要のない、割り当ておよび解放操作のシーケンスを処理できることを保証できます。組み込みシステムの問題は、最悪の場合でも成功を保証するには、断片化なしで必要なRAMよりもはるかに多くのRAMが必要になることです。
スーパーキャット2018年

@supercatそうですね。本当に熱狂的でした。これらの保証の正式な証拠があります。
モニカ

2

さて、あなたのPICはメモリの点でどれくらい大きいですか?

mallocは、メモリを割り当てるための非常に非効率的な方法です。それに関する問題は、頻繁な解放とmallocによってメモリが断片化する可能性があり、メモリが数キロバイトしかない場合、割り当ての失敗がすべて一般的すぎることです。小さいチップまたは以前のPIC18を使用している場合、マイクロチップはmallocを実装するのが非常に困難(または場合によっては不可能)と見なしたか、十分に使用されなかったため、mallocをサポートしていない可能性があります。価値がある。それは言うまでもありませんが、非常に低速でもあります。すでに利用可能な静的バッファを使用する1サイクルと、mallocを実行するために数百から1,000サイクルのサイクルを調べています。

静的に割り当てたい場合は、sprintf関数のバッファー(存在する場合、約128バイト)、SDカードのバッファー(存在する場合)などを作成し、mallocが不要になるまで続けます。理想的には、それが絶対に必要な場所でのみ使用し、静的な割り当てを回避できないが、これらの状況は通常まれであり、おそらくより大きな/より強力なマイクロコントローラーを検討する必要がある兆候です。

また、PIC18で「オペレーティングシステム」を開発/移植し、マイクロコントローラーをサポートしている場合は、おそらく静的割り当てがサポートされています。たとえば、SQLite3は静的な割り当てをサポートしています-大きなバッファー配列を割り当て、マイクロコントローラー向けではないにもかかわらず、可能な場合はそれを使用します。そうでない場合は、小さなPIC18用に設計されていることを確認しますか?


128KのRAMを搭載したPIC18F87J11を使用していますが、それで十分ですか?
stef '12 / 12/14

ステファノ、そのチップには3,904バイトのRAMがあります。128Kのプログラムフラッシュメモリを搭載しています。
W5VO

@Stefao Salati-3.8KBは小さい。
Thomas O

申し訳ありませんが..とにかくそれで十分だと思いますか?
stef '12 / 12/14

@Stefano Salati、謝罪する必要はありません。あなたは本当にそれを推進していると思います。それは機能するかもしれませんが、パフォーマンスと空きメモリからチャンクを取ります。
Thomas O

2

組み込みソフトウェアを検討malloc()free()ている場合は、uC / OS-IIおよびOSMemGet()を参照することをお勧めしますOSMemPut()。一方でmalloc()あなたは、メモリの任意のブロックを割り当てさせ、OSMem*()あなたに事前に割り当てられたプールから固定サイズのブロックを与えます。このアプローチはmalloc()、静的割り当ての柔軟性と堅牢性のバランスが取れていると思います。


0

私の知る限り、これを正しく行うには、ある種のメモリ管理ユニット(MMU)を備えたデバイスを実際に見ている必要があります。PIC18シリーズの動的割り当てメカニズムは存在しますが、実際にはそれほどしっかりしているわけではありません-PIC18シリーズの限界を押し広げるファームウェアに取り組んでいる誰かと言えば、あなたが得るつもりはないと言えるでしょう。あなたがメモリマネージャにすべてのオーバーヘッドを費やすなら、かなり大きなアプリケーションがあります。

より良い解決策:それが何をしているか、そしてなぜそれがダイナミックアロケーションを必要とするのかを理解しようとします。静的割り当てで機能するようにリファクタリングできないかどうかを確認してください。(これが単に不可能である場合もあります-ライブラリ/アプリケーションが自由にスケーリングする何かを実行するように設計されている場合、またはそれが受け入れることができる入力の量の限界がない場合)。あなたがやろうとしていることについては、代わりに静的割り当てを使用することが可能である(そしておそらく非常に簡単でさえある)ことに気付くかもしれません。


1
あなたは間違っています。MMUを使用すると、外部メモリとのインターフェイスが可能になります(PIC上の4kBよりも多い可能性があります)。MMUの有無にかかわらず、動的割り当てと静的割り当てにほとんど違いはありません。仮想メモリを使い始めると違いがありますが、それはmallocに正接するだけです。
ケビンフェルメール

1
初期のMacintoshコンピューターにはMMUがなかったという事実にもかかわらず、初期のMacintoshプログラマーはmalloc()とfree()(またはそれらのPascalの同等のもの)を頻繁に使用していました。malloc()を「正しく」使用するにはMMUが必要であるという考えは、私には正しくないようです。
davidcary 2011年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.