Dynamisches Zuweisen von Speicher für eine eingebettete Anwendung

Ich arbeite an einem Projekt, das die Verwendung einer MCU erfordert, um Rahmenpakete mit unbekannter Rahmenlänge beim Empfang zu empfangen, aber jeder Empfang hat ein Oktett, aus dem Sie die Anzahl der noch zu empfangenden Rahmen ableiten und somit die Länge des gesamten Rahmens berechnen können .

Um zu vermeiden, dass dem empfangenen Rahmen ein fester Speicher zugewiesen wird, der möglicherweise nicht aufgebraucht wird (wenn die Länge des empfangenen Rahmens geringer als die maximale Rahmenlänge ist), bin ich der Meinung, dem verbleibenden Rahmen dynamisch einen Speicher zuzuweisen zu erhalten.

Zum Beispiel. Nehmen wir ein Paket mit 20 Oktetts an und das 3. Oktett gibt Ihnen die Anzahl der verbleibenden Oktetts an, die noch zu empfangen sind (was maximal 2, 3 oder sogar 17 Oktetts sein können). Anstatt ein Register der Größe 17 zu erstellen, das möglicherweise nicht aufgebraucht wird, wie kann ich diesen Speicher speziell für eine eingebettete Anwendung dynamisch zuweisen, sodass ich, wenn das 3. Oktett feststellt, dass 6 Oktetts zu empfangen sind, einfach a Registrieren Sie sich für den Rest des Frames mit Größe 6, ohne "malloc" zu verwenden.

Programmiersprache ist C.

Ich hoffe meine Frage ist klar genug. Bitte teilen Sie Ihre Ansichten mit, da ich dies bestmöglich angehen muss.

Danke.

Gibt es einen Grund, warum Sie malloc nicht verwenden möchten?
Welchen Vorteil haben Sie, wenn Sie den zusätzlichen Speicher nicht verbrauchen? Sie müssen die MCU immer noch so dimensionieren, dass genügend RAM für das größte Paket vorhanden ist, das Sie empfangen können.
@Bruno, würden Sie die Verwendung von malloc für eine eingebettete Anwendung mit einer RAM-Größe von etwa 2 KB empfehlen und an die Tatsache denken, dass der Speicher konjugiert ist.
@markrages Ich verstehe Ihren Standpunkt, aber ich möchte sehen, ob es irgendwie möglich ist, Speicher zu sparen, da die tatsächliche maximale Größe etwa 128 Byte beträgt, was nicht immer vollständig aufgebraucht ist. Warum also nicht helfen, den verbleibenden Speicher für andere Vorgänge zu nutzen? ?
Was machst du mit dem Rest? Sie müssen bereit sein, dass die maximale Paketgröße hereinkommt, oder?
@PaulA. Das hängt von der Menge an freiem Speicher ab, den Sie haben. Beachten Sie, dass die Verwendung eines dynamischen Zuordnungsschemas immer einen Overhead mit sich bringt. Wenn die Größe Ihrer Daten also nicht viel größer als 20 Bytes ist, ist es möglicherweise besser, Blöcke mit fester Größe zu verwenden.
Sie sollten erläutern, was Sie mit "einer MCU" meinen. Wenn Sie von einem winzig kleinen eingebetteten Prozessor sprechen, der nichts anderes tut, lautet die Antwort: Verwenden Sie Ihren gesamten Speicher für die Aufgabe, machen Sie sich keine Gedanken über die dynamische Zuweisung. Wenn es sich um einen 32-Bit-ARM handelt, auf dem Linux ausgeführt wird, und es viele andere Dinge gibt, die Speicher verwenden, dann ja, gehen Sie dynamisch. Wie viel Arbeitsspeicher befindet sich im System und wofür wird es sonst verwendet?

Antworten (2)

In diesem Fall würde ich sagen, dass der beste Ansatz wahrscheinlich darin besteht, einfach die maximale Speichergröße zuzuweisen und sie auch für so viele andere Dinge wie möglich wiederzuverwenden.
Einige Compiler haben eine Option für Variablen, um Speicherplatz zu teilen, vorausgesetzt, sie sind nicht gleichzeitig aktiv. Beispielsweise hat der (jetzt durch HI-Tech C ersetzte) PIC18 C-Compiler ein overlayAttribut, das mit Variablen verwendet werden kann, um dies zu tun.
Es kann auch mit Arrays variabler Größe umgehen, was perfekt für das wäre, was Sie tun möchten (weniger Overhead als malloc). Ich würde prüfen, ob Ihr Compiler dies tun kann.

@Öl Glaser. Danke für diesen Punkt. Ich benutze den Keil-Compiler und das Atmel Studio 6. Ich weiß, ob sie solche Funktionen haben!
Zugegeben, dies scheint ein schlechter Fall für die dynamische Zuordnung zu sein, insbesondere auf einer eingebetteten Plattform. Die dynamische Zuweisung ist am nützlichsten, wenn Sie buchstäblich nicht wissen, wie viel Speicher benötigt wird, dh die Benutzerinteraktion provoziert die Speicherzuweisung. Wenn ich nichts vermisse, klingt es so, als ob Sie genug Headroom für eine maximale Anzahl von Paketen mit maximaler Größe im schlimmsten Fall benötigen. Warum also nicht so viel Speicher zuweisen, anstatt eine Lösung zu überarbeiten? Außerdem, wenn Sie den dynamischen Weg auf einer speicherbeschränkten Plattform gehen und nicht aufpassen, werden Sie vom mürrischen Freund der dynamischen Zuordnung, Fragmentation, gebissen.

Auf vielen Mikrocontrollersystemen weisen Compiler und Linker Daten von unten und/oder oben im RAM zu; Ungenutzter RAM befindet sich normalerweise in einem zusammenhängenden Bereich, und es ist im Allgemeinen möglich, den Linker davon zu überzeugen, dem Programmierer die Adressen des Anfangs und des Endes dieses Bereichs zur Verfügung zu stellen (z. B. könnte man den Linker bitten, eine Ein-Byte-Variable als allerletztes vor dem freien Bereich und ein weiteres als allererstes danach; die Adressen dieser Variablen würden den freien Bereich abgrenzen).

Obwohl viele Systeme eine malloc()Funktion anbieten, ist sie in vielen Szenarien komplizierter als nötig. Wenn man beispielsweise Objekte auf der Grundlage von zur Laufzeit empfangenen Informationen zuweisen muss, Objekte aber immer in der umgekehrten Reihenfolge der Zuweisung freigegeben werden, kann man einfach einen Zeiger auf den "nächsten verfügbaren Platz" behalten. Um ein Objekt zuzuweisen, kopieren Sie diesen Zeiger, fügen Sie ihm die Größe des neuen Objekts hinzu und geben Sie den kopierten Zeiger zurück. Um ein Objekt (und alles, was danach zugewiesen wurde) freizugeben, setzen Sie einfach den "nächster verfügbarer Platz"-Zeiger auf den Anfang dieses Objekts.

Einige Szenarien sind etwas komplexer als bei diesem Ansatz zulässig, benötigen aber dennoch keinen vollständigen „malloc/free“-Ansatz. Beispielsweise kann man in einigen Szenarios zwei Gruppen von Objekten haben, die untereinander der Last-in-First-out-Regel gehorchen, aber Objekte in einer Gruppe können die in der anderen überleben. Um mit dieser Situation fertig zu werden, verwenden Sie einen "nächster verfügbarer Platz"-Zeiger, der am Ende des freien Platzes beginnt, und einen "vorheriger verfügbarer Platz"-Zeiger, der oben beginnt. Ordnen Sie die Dinge in der ersten Gruppe wie zuvor zu. Subtrahieren Sie für diejenigen in der zweiten Gruppe die Größe des neuen Objekts vom Zeiger "zuvor verfügbarer Speicherplatz" und geben Sie das Ergebnis zurück. Um ein Objekt in der zweiten Gruppe (und alle danach zugeordneten Objekte der zweiten Gruppe) freizugeben,

Beachten Sie, dass mallocundfreesind so konzipiert, dass Objekte in der Mitte des Speichers freigegeben werden können, während Objekte davor und danach gültig bleiben. Das kann manchmal nützlich sein, kann aber auch zu Speicherfragmentierung führen. Wenn die eigenen Objekte nicht in ein Last-in-First-out-Modell passen, kann es eine gute Idee sein, Objekte verschiebbar zu machen. Beispielsweise könnte man eine Reihe von Objekten unterschiedlicher Größe halten, die nacheinander im Speicher gespeichert werden, solange Platz vorhanden ist. Wenn der Speicher voll wird (oder zu einem geeigneten Zeitpunkt davor), würde man das erste Objekt, das noch nicht gelesen wurde, an den Anfang der Warteschlange kopieren, das nächste Objekt, das unmittelbar darauf folgt, usw. bis Alle Objekte waren kopiert worden, wodurch der freie Platz, der sich am Anfang der Warteschlange befunden hatte, bis zum Ende konsolidiert wurde. Man muss beim Verschieben von Daten vorsichtig sein, um sicherzustellen, dass die Zeiger auf diese Daten entsprechend aktualisiert werden, aber das ist oft nicht allzu schwierig. Das Verschieben von Speicher kann mehr CPU-Zyklen erfordern als das Verwalten diskontinuierlicher Bereiche mit freiem Speicherplatz, aber das Verhalten des Ansatzes mit beweglichem Speicher kann vorhersehbarer sein.