Forum: Compiler & IDEs Speicherplatz freigeben?


von mr.chip (Gast)


Lesenswert?

Hallo

Für mein aktuelles Projekt (Bilderkennung) komme ich ziemlich an die
Grenzen des Speichers meines AVR. Nun wird mein Bild schrittweise
analysiert. Ein erster Schritt benötigt eine Anzahl Variabeln
(insbesondere Arrays), die später nicht mehr benötigt werden und nur
viel Platz wegnehmen.

Wie kann man solche Variabeln wieder 'löschen'? Natürlich könnte man
sie lokal in einer Funktion definieren, doch leider werden sie auch in
ISRs benötigt - es sind also Globalvariabeln.

Gruss

Michael

von alex (Gast)


Lesenswert?

Variablen global definieren ist ein schlechter programmierstill.
Deklariere die Varialen lokal, und übergebe dann nur einen Pointer auf
die Daten, an die sub routine.

von Michael J. (jogibaer)


Lesenswert?

Hallo,

das würde mich mal auch interessieren.

Das mit dem Zeiger ist ja klar, aber wie macht man daß bei
einer Interruptroutine ?
Die ruft der Prozessor ja selber auf; da kann ich nichts übergeben.

Wie kriegt man also eine Verbindung zwischen der Variablen der ISR und
der einen lokalen Funktion ?

Ich wüßte auf die schnelle keinen praktikablen Weg.

Jogibär

von johnny.m (Gast)


Lesenswert?

Das geht entweder über globale Variablen (wobei man das volatile nicht
vergessen darf) oder eben (elegant), indem man die Bearbeitung des
Interrupt-Ereignisses an sich nicht in der ISR durchführt, sondern dort
nur ein Flag setzt und den Rest im Hauptprogramm (mit lokalen Variablen)
macht. Letztere Variante geht natürlich nicht in Fällen, wo es wirklich
zeitkritisch ist. Da bleibt einem dann nichts anderes übrig, als global
zu denken;-)

von Karl heinz B. (kbucheg)


Lesenswert?

> Das mit dem Zeiger ist ja klar, aber wie macht man daß bei
> einer Interruptroutine ?
> Die ruft der Prozessor ja selber auf; da kann ich nichts übergeben.

Ohne eine globale Variable kommst du da nicht weg.
Aber die globale Variable kann ein Pointer sein, welcher
dann auf die eigentlichen Daten zeigt.

struct MeineDaten
{
  int MemberA;
  int MemberB;
  char Buffer[200];
  unsigned char Image[400];
};

volatile struct MeineDaten* pData;

ISR( was_auch_immer_vect )
{
  if( pData ) {
    // mach was mit den Daten
    pData->MemberA = 5;
    pData->MemberB = 8;
  }
}

void foo()
{
  struct MeineDaten Data;

  // die lokalen Variablen für die ISR bereitstellen

  pData = &Data;

  //
  // so , jetzt kann die ISR arbeiten
  //

  // funktion wird verlassen, die ISR wieder von den
  // Daten abklemmen
  pData = NULL;
}

int main()
{
   .....
   foo();

   while( 1 );
}

von Karl heinz B. (kbucheg)


Lesenswert?

> Ein erster Schritt benötigt eine Anzahl Variabeln
> (insbesondere Arrays), die später nicht mehr benötigt werden und
> nur viel Platz wegnehmen.

Genau diese Aufgabenstellung ist die Grundidee hinter einer
union:

* Ein Programm läuft in Abschnitten ab.
* Jeder Abschnitt hat seine eigenen Variablen, die nur in diesem
  Abschnitt gebraucht werden
* Ausserhalb des Abschnittes sind die Variablen nutzlos und liegen
  nur im Speicher rum
* Mittels einer union kann vereinbart werden, dass die Variablen
  mehrerer Abschnitte quasi übereinandergelegt werden sollen und
  damit verschiedene Abschnitte immer denselben Speicher benutzen.

von mr.chip (Gast)


Lesenswert?

Hallo

@Karl Heinz: Das hört sich schlüssig an! Werde es dann wohl so
machen. Irgendwie dachte ich an die Union, getraute mich aber nicht so
recht ;-)

Gruss

Michael

von mr.chip (Gast)


Lesenswert?

Hallo

Nochmals @Karl Heinz: Hört sich doch nicht so schlüssig an, weil: Eine
Union kann ja nur eine Variable pro Zeitpunkt speichern. Wenn ich nun
aber in meinem Programm in Abschnitt A zehn einfache Variabeln und fünf
längere Arrays habe und in Abschnitt B dann einfach ein längeres Array,
dann geht das leider nicht mit Unions.

Was haltet ihr von den Funktionen malloc() und free()?

Gruss

Michael

von Rolf Magnus (Gast)


Lesenswert?

Wieso sollte das mit Unions nicht gehen? Mit malloc/free wird's auch
gehen, aber bringt halt einen gewissen Overhead mit sich.

von mr.chip (Gast)


Lesenswert?

Kann eine Union denn mehrere Variabeln zum gleichen Zeitpunkt aufnehmen?
Hmmm...ich könnte für jeden Programmabschnitt ein struct 'reinpacken!
lichtaufgeht

Andere Frage: Overhead bei malloc/free? Wenn das alle paar Sekunden
geschieht, sollte das doch nicht allzuviel ausmachen?

von Rolf Magnus (Gast)


Lesenswert?

> Hmmm...ich könnte für jeden Programmabschnitt
> ein struct 'reinpacken! *lichtaufgeht*

Bingo!

> Andere Frage: Overhead bei malloc/free? Wenn das alle paar
> Sekunden geschieht, sollte das doch nicht allzuviel ausmachen?

Zeitlich vermutlich nicht. Du mußt allerdings auch noch den
Speicherverbrauch dazurechnen. Einerseits brauchen die Funktionen
selbst wieder Flash, andererseits braucht die Speicherverwaltung noch
zusätzliches RAM.
Ich weiß ja nicht, um welchen AVR es geht und wieviele Ressourcen noch
verfügbar sind. Ehrlich gesagt weiß ich auch nicht, wieviel genau die
Speicherverwaltung kostet.

von mr.chip (Gast)


Lesenswert?

Noch eine Frage: Muss ich irgend etwas spezielles beachten, wenn ich
zwischen den verschiedenen Variabeln in der union wechsle? Ausser, dass
ich sie vor Gebrauch natürlich wieder mit einem sinnvollen Wert
initialisieren muss ;-)

von Rolf Magnus (Gast)


Lesenswert?

Mir würde nichts weiteres einfallen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Ehrlich gesagt weiß ich auch nicht, wieviel genau die
> Speicherverwaltung kostet.

10 Bytes statischen RAM-Verbrauch, sowie 2 Bytes RAM
zusätzlich pro alloziertem Block, um die Größe dieses Blocks
aufzuzeichnen.  1-Byte-Blöcke werden auf 2 Bytes aufgerundet.

542 Bytes Code auf den ,kleinen' Prozessoren (die kein MOVW
und MUL haben), 498 Bytes Code auf den großen Prozessoren.

Also vielleicht nicht gerade sinnvoll für einen ATtiny2313 :),
ab einem ATmega8 kann man drüber nachdenken, ab einem ATmega32
interessiert der Ressourcenverbrauch wohl kaum noch, da bleibt
dann nur noch die Frage nach den möglichen Auswirkungen der
Speicherfragmentierung.  Da es im Thread um Bildverarbeitung
geht, wird es wohl nicht gerade der allerkleinste AVR sein.

von mr.chip (Gast)


Lesenswert?

Hallo

Ist ein Mega32 - Hauptproblem ist ganz klar das RAM (2 kB + 32 kB
extern (dämlich angesteuert über 4024 als Adress-Counter)), das
Programm passt locker rein und auch die Rechengeschwindigkeit ist ganz
ok (schnellere Echtzeitauswertung kann man auf einem AVR aber
vergessen).

Mit unions funktioniert das ganze eigentlich am besten - besser als mit
malloc() und free(), denn hier müsste jede einzelne Variable angefordert
und wieder entfernt werden, mit entsprechender Pointerorgie, bei der
union kann man bequem ein paar Structs für jeden Programmabschnitt
machen, die dann nacheinander benutzt werden. Einziger Nachteil: Man
schreibt genug: union.struct.variable - und ich weiss nicht, wie
schnell da der Zugriff intern gehandhabt wird.

Gruss

Michael

von Karl H. (kbuchegg)


Lesenswert?

Kleiner Tip:
Mittels Makros hat sich schon so mancher so manchen
Schreibaufwand eingespart.

#define VARIABLE  union.struct.variable

und schon wird aus einem

   union.struct.variable = 5;

ein simples

   VARIABLE = 5;

Nutze die Macht, Luke. Äh, mr. chip

von Karl H. (kbuchegg)


Lesenswert?

> und ich weiss nicht, wie
> schnell da der Zugriff intern gehandhabt wird.

Da beim Zugriff alles statisch ist, und der Compiler
die Adressen ausrechnen kann, kannst du mal davon ausgehen
dass er das auch tun wird.

von mr.chip (Gast)


Lesenswert?

> Da beim Zugriff alles statisch ist, und der Compiler
> die Adressen ausrechnen kann, kannst du mal davon ausgehen
> dass er das auch tun wird.

Das heisst dann, ein Zugriff auf eine 'union.struct.variable' ist vom
Aufwand her äquivalent zu einem Zugriff auf 'variable'?

von Karl H. (kbuchegg)


Lesenswert?

Exakt

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Mit unions funktioniert das ganze eigentlich am besten - besser als
> mit malloc() und free(), denn hier müsste jede einzelne Variable
> angefordert und wieder entfernt werden,

Ist eine Frage der Lebenszeit.  Wenn die Variablen alle praktisch
immer leben, dann sind die unions sicher am besten.  Wenn du eine
stochastische Verteilung der Lebensdauer hast, belegst du bei der
malloc()-Variante halt nur den Speicher, den du gerade brauchst.

von mr.chip (Gast)


Lesenswert?

> Ist eine Frage der Lebenszeit.  Wenn die Variablen alle praktisch
> immer leben, dann sind die unions sicher am besten.  Wenn du eine
> stochastische Verteilung der Lebensdauer hast, belegst du bei der
> malloc()-Variante halt nur den Speicher, den du gerade brauchst.

Klingt logisch. Allerdings habe ich wie erwähnt eine ganz klare
Aufstellung, wann welche Variabeln existieren. Im ersten Abschnitt des
Programms jene, im zweiten andere. Es gibt weder Überlappungen noch
'Zufälligkeiten'. Ich denke, dies ist auf einem kleinen
Mikrocontroller bei derart speicherintensiven Anwendungen auch die
Regel - man muss jedes einzelne Byte genau einteilen, sonst hat das
wüste Folgen...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Ich denke, dies ist auf einem kleinen Mikrocontroller bei derart
> speicherintensiven Anwendungen auch die Regel - man muss jedes
> einzelne Byte genau einteilen, sonst hat das wüste Folgen...

Würde ich so nicht ganz stehen lassen.  Stochastik kann ebenfalls gut
funktionieren, auch wenn es auf den ersten Blick wie Chaos aussieht.

Die Diskussion erinnert mich an den Streit, was das bessere
Vernetzungsprinzip ist: die ,,reine Lehre'' besteht darauf, dass
jeder
nur dann senden kann, wenn er ,,dran'' ist.  Zu diesem Zweck wird
ein
Staffelstab herumgereicht, der jeder Station sagt, wann sie dran ist.
Wenn sie nichts zu senden hat, gibt sie diesen weiter.

Die Alternative ist, dass jeder sendet, ,,wann er will'', nur zuvor
mal nachsieht, ob nicht vielleicht gerade jemand anders sendet.  In
diesem Fall ,,ein bisschen'' wartet.

Das erste nennt sich `token ring', das zweite `Ethernet'.
Mittlerweile dürfte ziemlich klar sein, wer der Gewinner dieses
Streits war.

Mit dem Speicher ist das ganz genauso.  Die Stochastik hat natürlich
ihre Grenzen: bei ,Verstopfung' ist das jeweilige deterministische
System zuverlässiger.  Der Tote Ring erreicht gleichmäßige
Übertragungsraten auch noch kurz vor der Sättigung, während Ethernet
in diesem Bereich durch die häufigen retries einbricht.  Wenn dein
Speicher also bis zum letzten Byte ausgereizt ist, wird die Stochastik
nicht mehr gut funktionieren, weil immer häufig der Zustand `out of
memory' zuschlägt.

von mr.chip (Gast)


Lesenswert?

> Wenn dein Speicher also bis zum letzten Byte ausgereizt ist, wird die
> Stochastik nicht mehr gut funktionieren, weil immer häufig der
Zustand > `out of memory' zuschlägt.

Ich kann sozusagen frei wählen, wie voll ich meinen Speicher haben will
- je mehr Speicherplatz ich zur Verfügung habe, desto besser wird meine
Bildauswertung. Von daher werde ich also so nahe wie möglich ans Limit
gehen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.