Forum: Mikrocontroller und Digitale Elektronik MEGA32U4 und malloc -> App stürzt ab :(


von Jan H. (janiiix3)


Lesenswert?

Guten Morgen (:

Ich habe ein da mal ein Problem..
Und zwar wenn ich in der Funktion versuche, mit malloc() Speicher frei 
zu schaufeln, funktioniert das ein paar mal.. ab und zu aber stürzt mir 
meine App. ab.
Mit einer festen Speichergröße (also einem Array) klappt alles wie es 
soll.
Mache ich was Grundlegendes falsch?
1
int8_t srchCmd(char *inBuff, char *srchCmd)
2
{
3
     char *cmdBeginn     = NULL;
4
     char *rawData      = NULL;
5
   uint8_t cmdStrLen      = strlen(srchCmd);
6
   uint8_t rawData_    = 0;
7
8
  if (inBuff == NULL || srchCmd == NULL)
9
  return -1;
10
11
  /*
12
  *  how much raw data we will received?
13
  */
14
  rawData = strchr(srchCmd,'x');
15
  if(rawData != NULL)
16
  while(*rawData++ == 'x')rawData_++;
17
      
18
  /*
19
  *    internal command buffer
20
  */
21
  char *cmdBeginn_ = (char*)malloc(sizeof(char)*10);  
22
  if (cmdBeginn_ == NULL)
23
  return -1;
24
25
  //char cmdBeginn_[26] = "";
26
27
  strcpy(cmdBeginn_,srchCmd);
28
   
29
  /*
30
  *  terminate cmd string
31
  */  
32
  cmdBeginn_[cmdStrLen-rawData_] = '\0';
33
  
34
  /*
35
  *  search beginning from our final command string
36
  */    
37
  cmdBeginn = strstr(inBuff,cmdBeginn_);
38
  if(cmdBeginn == NULL)
39
  return -2;
40
  
41
  /*
42
  *    terminate end of searched string
43
  */
44
  cmdBeginn[cmdStrLen] = '\0';
45
46
  /*
47
  *    copy the command to buffer
48
  */
49
  strcpy(inBuff,cmdBeginn);
50
  
51
  free(cmdBeginn_);
52
  
53
  return 0;
54
}

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Jan H. schrieb:
> Und zwar wenn ich in der Funktion versuche, mit malloc() Speicher frei
> zu schaufeln, funktioniert das ein paar mal.. ab und zu aber stürzt mir
> meine App. ab.

Dynamische Speicherverwaltung kann man auf einem µC eigentlich kaum 
verwenden.

Erstens gibt es nirgends ein free, d.h. der RAM wird ratzfatz 
aufgebraucht.

Und zweitens funktioniert free ohne Speicherverwaltung nicht, d.h. der 
freigegebene RAM kann nicht wieder genutzt werden.

Du solltest alles als statische Arrays deklarieren oder ein einziges mal 
einen malloc machen und den Speicherbereich dann immer wieder 
weiterverwenden. Dann kann man aber auch gleich ersteres machen :)

von Jan H. (janiiix3)


Lesenswert?

Mampf F. schrieb:
> Erstens gibt es nirgends ein free, d.h. der RAM wird ratzfatz
> aufgebraucht.

Ist doch vorhanden?

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Jan H. schrieb:
> Mampf F. schrieb:
>> Erstens gibt es nirgends ein free, d.h. der RAM wird ratzfatz
>> aufgebraucht.
>
> Ist doch vorhanden?

Ah okay, dennoch gilt der Rest ;-)

von PittyJ (Gast)


Lesenswert?

Soweit ich es kenne, sollten malloc() und free() gehen.
Nur ist die Gefahr von Problemen größer, da weniger Speicher überhaupt 
dafür verwendet werden kann, und dieser dann stark fragmentiert werden 
kann.

In dem Programm oben werden immer genau 10 Bytes alloziert, das könnte 
mit einem statischen Buffer besser gehen.
Ausserdem gibt es returns vor dem free(), so dass Speichern verloren 
gehen kann.


Und für mich heisst das immer noch Programm und nicht App.

von Root (Gast)


Lesenswert?

Den Speicher auf dem Stack zu legen wäre hier auch nicht falsch , die 
Größe ist ja immer 10. und der Speicher wird nach dem Rückkehren aus der 
Funktion nicht mehr benötigt

von Holm T. (Gast)


Lesenswert?

Ich hatte vor ca. 10 Jahren eine Art Schnittstellenkonverter geschrieben 
der einen Datenstrom in Teile flexibler Länge aufsplittete, die Elemente 
in einer verketteten Liste zwischenspeicherte und in anderer 
Reihenfolge/Dimension/Geschwindigkeit usw. wieder ausgab.
Ich habe dazu ohne daran großartig zu zweifeln malloc/free der avr-libc 
benutzt ....Jörg hat die lib dann mit mir debuggt ..sie sollte also 
damals dann weitgehend fehlerfrei gewesen sein was sie zu Beginn meiner 
Arbeiten nicht war. In meinem Programm wurde aber "nach einem Durchlauf" 
jeweils die gesamte Liste wieder frei gegeben..da funktionierte auch die 
Defragemntierung das RAMs und der lief nicht langsam zu.
Das Ganze war ein paar Jahre in der Industrie auf Atmega644p in mehreren 
Varianten problemlos im Einsatz.

Schaue mal beim Programmlauf nach folgenden Variablen, Freelist und 
heap...
1
DPRINTF("FLP: %04x SZ: %04x NX: %04x ",__flp,__flp->sz, __flp->nx);
2
DPRINTF("malloc_start: %04x brkval: %04x\r\n",__malloc_heap_start,__brkval);


Die Meinung das man dynamischen Speicher auf einem Mikro nicht nutzen 
kann ist hier stark vertreten, aber Blödsinn, es funktioniert und ich 
hatte damals keine andere Wahl. In "rechteckige" Felder verpackt hätten 
die Daten keinen Platz im Speicher gehabt.
Der Vorschlag die Daten auf den Stack zu legen ist auch eine praktikable 
Variante, aber wie auch mit malloc/free muß man höllisch aufpassen den 
Speicher symmetrisch mit den richtigen Pointern zu behabndeln..

Gruß,

Holm

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Jan H. schrieb:
> (char*)malloc(sizeof(char)*10);

Der typecast ist überflüssig, und sizeof char ist per Definition immer 
1.

von Einer K. (Gast)


Lesenswert?

Holm T. schrieb:
> Die Meinung das man dynamischen Speicher auf einem Mikro nicht nutzen
> kann ist hier stark vertreten, aber Blödsinn, ...

Naja...
Einen fragmentierten Speicher wird man nur durch einen Reset wieder los.
Ebenso verhält es sich mit Speicherleichen auf dem Heap.


Ich vertrete die Meinung:
1. verzichte darauf, wenn möglich
2. erhöhte Aufmerksamkeit/Disziplin bei der Verwendung.

Wie derbe die Verwendung nach hinten los gehen kann, sieht man an der 
Eingangsfrage.

Oder anders:
> Wenn der Esel zu wenig Probleme hat,
> dann geht er aufs Eis.

von Jan H. (janiiix3)


Lesenswert?

Rufus Τ. F. schrieb:
> Jan H. schrieb:
>> (char*)malloc(sizeof(char)*10);
>
> Der typecast ist überflüssig, und sizeof char ist per Definition immer
> 1.

Danke für den Hinweis.

von Mitlesa (Gast)


Lesenswert?

Root schrieb:
> Den Speicher auf dem Stack zu legen wäre hier auch nicht falsch , die
> Größe ist ja immer 10. und der Speicher wird nach dem Rückkehren aus der
> Funktion nicht mehr benötigt

Das scheint beim TO noch nicht angekommen zu sein.

Ausserdem ist nicht unter allen Bedingungen gewährleistet dass
nach dem malloc() auch später ein free() ausgeführt wird.

Siehe
1
  /*
2
  *  search beginning from our final command string
3
  */    
4
  cmdBeginn = strstr(inBuff,cmdBeginn_);
5
  if(cmdBeginn == NULL)
6
  return -2;

von Pandur S. (jetztnicht)


Lesenswert?

Das Problem loest man doch ganz anders, ohne kopieren, direkt auf dem 
Kommunikationsringbuffer. Eine Zustandsmaschine, die auf ein Null, oder 
Timeout wartet, und falls das Null kam, auf den vorgaengigen String 
reagiert.

von Einer K. (Gast)


Lesenswert?

Jan H. schrieb:
> cmdBeginn = strstr(inBuff,cmdBeginn_);
Solche Zeilen mag ich gar nicht....

In der Regel werfe ich solche Programmtexte weg.
Verweigere das weiter lesen.

Das Problem ist nicht strstr()

Sondern die Bezeichnerähnlichkeit: cmdBeginn vs. cmdBeginn_

Ich halte sowas für eine glänzende Methode, sich selber ein Fettnäpfchen 
vor die Füße zu stellen.

von avr (Gast)


Lesenswert?

Arduino F. schrieb:
> Einen fragmentierten Speicher wird man nur durch einen Reset wieder los.
> Ebenso verhält es sich mit Speicherleichen auf dem Heap.

Malloc heißt nicht, dass man fragmentierten Speicher hat. Ich finde 
fragmentlose dynamische Speicherverwaltung ist vorzuziehen, wenn die 
Software dadurch an Übersicht gewinnt.

von Einer K. (Gast)


Lesenswert?

avr schrieb:
> wenn die Software dadurch an Übersicht gewinnt.

Bei dem obigen Codefetzen, gibt es einige Stellen, wo man Übersicht dazu 
gewinnen könnte.

Der Verzicht von malloc() und free() würde dazu gehören, da sie hier 
völlig unnötig sind.
(so wie ich das sehe)

von avr (Gast)


Lesenswert?

Von dem Code müssen wir auch nicht reden, da stimme ich dir zu. Nur 
allgemein spricht bei richtiger Verwendung nichts gegen dynamische 
Speicherverwaltung auf Mikrocontrollern.

von MaWin (Gast)


Lesenswert?

Jan H. schrieb:
> Ich habe ein da mal ein Problem

Mehr als das.

Erstens gibt es keine App auf Mega32u4.

Zweitens kann man unter C zwar malloc verwenden, aber nur wenn der heap 
zuvor eingerichtet wurde. Wie gross hast du ihn denn eingerichtet ?

Drittens hast du

Jan H. schrieb:
> mit malloc() Speicher frei zu schaufeln

offenkundig ein massives Verständnisproblem was malloc tut. Eher das 
Gegenteil von freischaufeln, nämlich belegen. Je mehr malloc man macht, 
um so weniger freien Speicher hat man.

Auch würde ich den Unsinn mit den gleichen Namen nur mal mit _ und mal 
ohne, sein lassen, das ist obfurscation, kein sinnvoller Stil.

Auch stellt sich die Frage, warum cmdBeginn_ fest für 9 Zeichen 
ausgelegt wird, was ist wenn in srchCmd mehr drinstehen ?

Und wenn man ein x in abdxxxdef sucht, warum kopiert man ganz abcxxxdef 
und nullt dann bei abcxxx das def weg ?

Klingt falsch.

Ein Grundlagenbuch über Programmierung wäre wohl angeraten.

Programmieren ist so einfach wie Lego, man muss nur vorgegebene 
Bausteine zum Gesamtwerk zusammenklipsen.

Du musst wohl erst lernen was Legosteine sind.

Vor den vielen Fehler- return nach dem malloc muss z.B. auch ein free 
hin.

avr schrieb:
> Malloc heißt nicht, dass man fragmentierten Speicher hat

Doch, in C schon.

von Stefan F. (Gast)


Lesenswert?

> Malloc heißt nicht, dass man fragmentierten Speicher hat
> Doch, in C schon.

Nein nicht unbedingt. Es kommt auf die Größe der Blöcke und die 
Reihenfolge an, in der man den Speicher belegt und wieder freigibt.

von Einer K. (Gast)


Lesenswert?

Stefan U. schrieb:
> und die
> Reihenfolge an, in der man den Speicher belegt und wieder freigibt.

Das ist ja das doofe....
Wer will da schon Buch führen müssen.

von Der Andere (Gast)


Lesenswert?

Stefan U. schrieb:
> Nein nicht unbedingt. Es kommt auf die Größe der Blöcke und die
> Reihenfolge an, in der man den Speicher belegt und wieder freigibt.

Wenn man zur Designzeit schon weiß welche Blöcke man wie groß braucht, 
dann kann man sich in den meisten Fällen auch ganz die dynamische 
Speicherverwaltung sparen.

avr schrieb:
> Malloc heißt nicht, dass man fragmentierten Speicher hat. Ich finde
> fragmentlose dynamische Speicherverwaltung ist vorzuziehen, wenn die
> Software dadurch an Übersicht gewinnt.

Daß die dynamische Speicherverwaltung auch Code und Datenoverhead bringt 
ist dir aber auch bewusst?
Und wie gesagt, wenn ich von vorneherein weiss was ich mit malloc 
brauche, dann kann ich in 80-95% der Fälle den Speicher auch gleich 
statisch belegen. Und das durchaus auch übersichtlich, wohingegen ein 
sauberes free() handling den Code durchaus unübersichtlicher machen 
kann.

Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht 
soweit, daß er sich an dynamische Speicherverwaltung bei doch so 
besonderen Umständen wagen sollte.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

MaWin schrieb:
> Vor den vielen Fehler- return nach dem malloc muss z.B. auch ein free
> hin.

Da gibt es ein nettes Konstrukt in C, das man verwenden kann ...
1
do {
2
    ...
3
    char *cmdBeginn_ = (char*)malloc(sizeof(char)*10);
4
    ...
5
    cmdBeginn = strstr(inBuff,cmdBeginn_);
6
    if(cmdBeginn == NULL)
7
        break;
8
9
    ....
10
} while (0);
11
free(cmdBeginn_);

Das ist oft ganz hilfreich, um ewige
1
if (...) {
2
  free(cmdBeginn_);
3
  return;
4
}

zu vermeiden :-)

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Der Andere schrieb:
> Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht
> soweit, daß er sich an dynamische Speicherverwaltung bei doch so
> besonderen Umständen wagen sollte.

+1

von Jan H. (janiiix3)


Lesenswert?

Der Andere schrieb:
> Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht
> soweit, daß er sich an dynamische Speicherverwaltung bei doch so
> besonderen Umständen wagen sollte.

Das sind immer die stärksten ;)
Ich nenne es nun mal "Applikation".

Vill. solltest du vorher mal deinen Horizont erweitern ;)

von Marco H. (damarco)


Lesenswert?

Es stürzt nicht ab sondern führt zu nicht gewollten Verhalten. Da du 
auch nicht prüfst ob der Bereich gültig ist den dir malloc übergibt. 
Denn so könnte man das abfangen. Beim ARM landet man im Defaulthandler. 
In diesem kann man dann dafür sorgen daß die Anwendung nicht Amok läuft.

von Felix F. (wiesel8)


Lesenswert?

Jan H. schrieb:
> Der Andere schrieb:
>> Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht
>> soweit, daß er sich an dynamische Speicherverwaltung bei doch so
>> besonderen Umständen wagen sollte.
>
> Das sind immer die stärksten ;)
> Ich nenne es nun mal "Applikation".
>
> Vill. solltest du vorher mal deinen Horizont erweitern ;)

Applikation:
Als Anwendungssoftware (auch Anwendungsprogramm, kurz Anwendung oder 
Applikation) werden Computerprogramme bezeichnet, die genutzt werden, um 
eine nützliche oder gewünschte nicht systemtechnische Funktionalität 
zu bearbeiten oder zu unterstützen.

Firmware:
Unter Firmware (engl. firm ‚fest‘) versteht man Software, die in 
elektronischen Geräten eingebettet ist. Sie ist zumeist in einem 
Flash-Speicher, einem EPROM, EEPROM oder ROM gespeichert und durch den 
Anwender nicht oder nur mit speziellen Mitteln bzw. Funktionen 
austauschbar.


Ich frage mich, wer hier seinen Horizont erweitern sollte...

mfg

von Einer K. (Gast)


Lesenswert?

Marco H. schrieb:
> Es stürzt nicht ab sondern führt zu nicht gewollten Verhalten.
Ach...
Da machst du aber feine Unterschiede...
Keiner will hier AVRs vom Tisch auf die Erde fallen lassen..

Marco H. schrieb:
> Da du
> auch nicht prüfst ob der Bereich gültig ist den dir malloc übergibt.
> Denn so könnte man das abfangen.
Wird doch gemacht!

Marco H. schrieb:
> Beim ARM landet man im Defaulthandler.
Wir sind hier aber nicht ARM.

Beim AVR gibts, dank gänzlich fehlendem Speicherschutz, keine 
zuverlässige Möglichkeit Heap-Stack Kollisionen zu erkennen.

von Der Andere (Gast)


Lesenswert?

Jan H. schrieb:
> Vill. solltest du vorher mal deinen Horizont erweitern ;)

Mag sein, du solltest auf jeden Fall deine Programmierkenntnisse 
erweitern.

Solange du völlig unnötig so dicke Speicherleaks auf einem kleinen µC 
bastelst obwohl man das mit einer popeligen lokalen Variablen hätte 
lösen können nehme ich vor dir ehrlich gesagt wenig Belehrung an.

An deiner Stelle wäre ich soooo klein mit Hut und würde mich bei den 
Usern "Root" und "Mitlesa" bedanken.

von avr (Gast)


Lesenswert?

Der Andere schrieb:
> Daß die dynamische Speicherverwaltung auch Code und Datenoverhead bringt
> ist dir aber auch bewusst?

Der geht im Rauschen unter. Natürlich geht es auch statisch. Aber 
wartungsfreundlicher geht es mit malloc. Wenn ich eine z.b. fifo Objekt 
habe, möchte ich nicht erst ein Array als Puffer dafür banlegen, sondern 
direkt die Größe übergeben.

Quasi fifo* f = create_fifo(128);
Die Puffer werden einmal dynamisch angelegt. Vielleicht gefällt das dir 
nicht, aber weniger und übersichtlicherer Code ist mir wichtiger als ein 
paar Bytes ram.

Und auch in c++ möchte ich die Größe auch nicht als Template parameter 
haben, weil damit das die Codegröße erhöht, wenn mehrere fifos genutzt 
werden. Besonders wenn diese in anderen Klassen/Funktionen genutzt 
werden.

von Der Andere (Gast)


Lesenswert?

avr schrieb:
> Natürlich geht es auch statisch. Aber
> wartungsfreundlicher geht es mit malloc.

Klar, wie man im Beispiel vom TO sieht ist das superwartungsfreundlich.
Sprich es ist freundlich für den der den Code warten muss denn er hat 
ordentlich zu tun bis er alle Speicherleaks gefunden hat.

Nur für den Kunden sind die vielen Abstürze nicht so freundlich.
:-p

avr schrieb:
> Quasi fifo* f = create_fifo(128);

Wir haben hier von 8 Bit µC geredet, nicht von 32 Bit oder PC Software

von Cyblord -. (cyblord)


Lesenswert?

avr schrieb:
> Quasi fifo* f = create_fifo(128);
> Die Puffer werden einmal dynamisch angelegt. Vielleicht gefällt das dir
> nicht, aber weniger und übersichtlicherer Code ist mir wichtiger als ein
> paar Bytes ram.

Allein die Behauptung, dynmaische Speicherverwaltung wäre per se 
übersichtlicher oder sauberer ist doch Unsinn. Diese Prämisse würde ich 
erstmal verneinen.

Wenn der benötigte maximale Speicher von vornherein bekannt ist, macht 
es einfach keinen Sinn diesen NICHT statisch anzulegen. Das ist 
übersichtlich und lässt einen den belegten Speicher direkt einsehen.

Beim klassischen µC Projekt steht nun mal der Speicher meistens fest. 
Und auch wenn ich mehrere FIFO Objekte benötigte, weiß ich im vorraus 
wieviele und allokiere das Objekt oder die Struktur entsprechend oft, 
aber trotzdem statisch.

Selbst wenn die benötigte Anzahl erst zur Laufzeit bekannt werden 
sollte, weiß ich trotzdem wie viele es maximal sein dürfen. Und die kann 
ich dann auch statisch anlegen weil ich den übrigen Speicher für nichts 
aufsparen kann.

Der seltene Fall wo dynmische Verwatlung sinn machen kann, ist eben der, 
wo zur Laufzeit entscheiden wird, wie viele Objekte vom Typ X und 
wieviele Objekte vom Typ Y benötigt werden.
Dann kann ich eben nicht einfach statisch maximal den Speicher voll 
machen sondern muss in der Tat dynamisch arbeiten.
Aber wie gesagt, dieser Fall kommt im klassischen µC Umfeld nicht os 
häufig vor.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Felix F. schrieb:
> Applikation:
> Als Anwendungssoftware (auch Anwendungsprogramm, kurz Anwendung oder
> Applikation) werden Computerprogramme bezeichnet, die genutzt werden, um
> eine nützliche oder gewünschte nicht systemtechnische Funktionalität
> zu bearbeiten oder zu unterstützen.

Tatsächlich spricht man auch bei µCs von Anwendung bzw. Applikation z.B. 
bei Steuergeräten, um den Code, der die eigentliche Funktionalität 
umsetzt, vom Rahmen-Code zu unterscheiden, der sich um die 
low-level-Dinge wie Kommunikation oder Zyklus-Steuerung kümmert.

> Ich frage mich, wer hier seinen Horizont erweitern sollte...

Ich mich auch.

Arduino F. schrieb:
> Marco H. schrieb:
>> Es stürzt nicht ab sondern führt zu nicht gewollten Verhalten.
> Ach...
> Da machst du aber feine Unterschiede...

Nun, unter Absturz verstehe ich, dass das Betriebssystem das Programm 
terminiert und aus dem Speicher entfernt, weil es irgendeine unzulässige 
Aktion durchführen will - von mir aus auch noch, wenn das Programm sich 
per abort() beendet, weil ein assert fehlgeschlagen oder eine 
unbehandelte Exception aufgetreten ist. Bei einem AVR gibt's das aber 
natürlich nicht, und es läuft immer irgendwie weiter. Es kann nicht 
terminiert werden, außer durch Trennen der Stromversorgung.
Daher wäre dann die Frage, was du bei einem AVR unter "abstürzen" 
verstehst.

> Beim AVR gibts, dank gänzlich fehlendem Speicherschutz, keine
> zuverlässige Möglichkeit Heap-Stack Kollisionen zu erkennen.

Deshalb ist statischer Speicher geschickter. Bei dem weiß man schon zur 
Compilezeit, wieviel davon insgesamt benötigt wird.

avr schrieb:
> Der Andere schrieb:
>> Daß die dynamische Speicherverwaltung auch Code und Datenoverhead bringt
>> ist dir aber auch bewusst?
>
> Der geht im Rauschen unter.

Auf dem PC schon, aber auf einem kleinen 8-Bitter nicht.

> Natürlich geht es auch statisch. Aber wartungsfreundlicher geht es mit
> malloc.

Was soll daran wartungsfreundlicher sein? Der obige Code enthält ein 
Memory-Leak, nur weil etwas dynamisch allokiert wird, dessen Größe 
eigentlich zur Compilezeit schon feststeht. Im obigen Fall hat der 
dynamische Speicher genau Null Vorteil und macht nur Probleme.

> Wenn ich eine z.b. fifo Objekt habe, möchte ich nicht erst ein Array als
> Puffer dafür banlegen, sondern direkt die Größe übergeben.

Darum geht es hier aber gar nicht. Hier geht es um eine Funktion, die an 
ihrem Anfang ein einfaches Array aus 10 Bytes dynamisch allokiert, es 
dann zwischendurch benutzt und an ihrem Ende (manchmal) wieder freigibt.

> Die Puffer werden einmal dynamisch angelegt. Vielleicht gefällt das dir
> nicht, aber weniger und übersichtlicherer Code ist mir wichtiger als ein
> paar Bytes ram.

Wenn man nur "ein paar Bytes ram" hat, können die plötzlich deutlich an 
Wichtigkeit gewinnen.

> Und auch in c++ möchte ich die Größe auch nicht als Template parameter
> haben, weil damit das die Codegröße erhöht, wenn mehrere fifos genutzt
> werden.

Wie kommst du darauf? Vom Hörensagen, oder hast du das getestet?

> Besonders wenn diese in anderen Klassen/Funktionen genutzt
> werden.

Warum sollte es einen Unterschied machen, wo die genutzt werden?

: Bearbeitet durch User
von Holm T. (Gast)


Lesenswert?

Arduino F. schrieb:
> Holm T. schrieb:
>> Die Meinung das man dynamischen Speicher auf einem Mikro nicht nutzen
>> kann ist hier stark vertreten, aber Blödsinn, ...
>
> Naja...
> Einen fragmentierten Speicher wird man nur durch einen Reset wieder los.
> Ebenso verhält es sich mit Speicherleichen auf dem Heap.

..meint ein "Arduino Fanboy"?
>
>
> Ich vertrete die Meinung:
> 1. verzichte darauf, wenn möglich
> 2. erhöhte Aufmerksamkeit/Disziplin bei der Verwendung.
>
> Wie derbe die Verwendung nach hinten los gehen kann, sieht man an der
> Eingangsfrage.
>
> Oder anders:
>> Wenn der Esel zu wenig Probleme hat,
>> dann geht er aufs Eis.
..und verbreitet hier seltsame Weisheiten..

Gruß,
Holm

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


Lesenswert?

Mampf F. schrieb:
> Da gibt es ein nettes Konstrukt in C, das man verwenden kann ...

Was die Leute alles so für Verrenkungen machen, nur damit sie einen
gezielten Sprung machen können, ohne das böse Wort „goto“ hinschreiben
zu müssen. :-))

Bezüglich des TE: solange es wirklich immer 10 Bytes sind, legt man
das wirklich besser auf dem Stack ab.  Allerdings hat man dort
keinerlei Schutz dagegen, dass einem der Stack dann nicht in die
globalen bzw. statischen Variablen reinrennt.  malloc() gibt sich da
wenigstens noch ein bisschen Mühe, den Überlauf-Fall abzusichern (und
gibt dann 0 zurück).

Warum man mit der blöden These, dynamischen Speicher auf Controllern
komplett zu vermeiden, nicht immer weiterkommt, hat Holm ja bereits
geschrieben.

Jan H. schrieb:
> //char cmdBeginn_[26] = "";
>
>   strcpy(cmdBeginn_,srchCmd);

Irgendwie passen die 10 allozierten Bytes überhaupt nicht zu den 26
im Kommentar.  Außerdem würde ich dort natürlich nur dann auf
strncpy() verzichten, wenn unter allen Umständen durch den Rest des
Programms technisch sichergestellt ist, dass der String in srchCmd
niemals länger als 9 Zeichen werden kann.

: Bearbeitet durch Moderator
von Holm T. (Gast)


Lesenswert?

Cyblord -. schrieb:
> Der Andere schrieb:
>> Und wer auf einem kleinen µC von "Apps" redet ist glaube ich noch nicht
>> soweit, daß er sich an dynamische Speicherverwaltung bei doch so
>> besonderen Umständen wagen sollte.
>
> +1

AVRstudio legte zumindest früher den Code irgendwie in "app" ab..
Wenn App ne Abkrüzung von Applikation ist kann man es noch durchgehen 
lassen..

Gruß,

Holm

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


Lesenswert?

Arduino F. schrieb:
> Beim AVR gibts, dank gänzlich fehlendem Speicherschutz, keine
> zuverlässige Möglichkeit Heap-Stack Kollisionen zu erkennen.

Jein: das malloc() der avr-libc hat einen Guard-Bereich gegenüber
dem Stack.  Wenn der erreicht wird, verweigert es die Allozierung.
Die Größe kann man als Nutzer festlegen, default ist 32.

Insofern ist es immer noch besser als blindes Allozieren auf dem
Stack, denn da wird nullkommanichts getestet, dass der Stack nicht
in die statisch belegten Daten reinrauscht.

Klar hilft das natürlich nichts, wenn man völlig planlos ist und
nach dem malloc() dann in eine riesig tiefe Rekursion reinrennt …

von Der Andere (Gast)


Lesenswert?

Jörg W. schrieb:
> malloc() gibt sich da
> wenigstens noch ein bisschen Mühe, den Überlauf-Fall abzusichern (und
> gibt dann 0 zurück).

Und was machst du dann? Die Led "Speicherüberlauf" setzen?

Jörg W. schrieb:
> Warum man mit der blöden These, dynamischen Speicher auf Controllern
> komplett zu vermeiden, nicht immer weiterkommt

Was ja auch niemand behauptet hat. Wohl aber daß man sie in 9 von 10 
Fällen vermeiden kann und dann auch tunlichst soll. Und daß man mit 
dynamischer Speicherverwaltung sich ganz schnell Probleme einfängt die 
deutlich schwieriger rauszufinden sind wie:

Jörg W. schrieb:
> dass einem der Stack dann nicht in die
> globalen bzw. statischen Variablen reinrennt

nämlich Speicherleaks und Fragmentierung.

Siehe das Beispiel des TOs. Ziemlich trivialer Code, auch wenn er mit 
seinen Variablennamen fast perfektes obfuscating betreibt, und schon 2 
Speicherleaks.

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


Lesenswert?

Der Andere schrieb:
> Jörg W. schrieb:
>> malloc() gibt sich da
>> wenigstens noch ein bisschen Mühe, den Überlauf-Fall abzusichern (und
>> gibt dann 0 zurück).
>
> Und was machst du dann? Die Led "Speicherüberlauf" setzen?

Das Problem musst du immer behandeln können.

Bei statischer Vorbelegung ist im Zweifelsfalle (wie bei Holm
seinerzeit) deine Ressource "RAM" nämlich schon viel eher alle,
und du kannst eine weiße Flagge zum Fenster raushängen.

Klar: wer solche Probleme gar nicht hat, muss sich daraum auch keine
Gedanken machen.  Nicht jeder wird aber in der glücklichen Lage sein,
bereits zur Compilezeit alles zu wissen.

> Und daß man mit
> dynamischer Speicherverwaltung sich ganz schnell Probleme einfängt die
> deutlich schwieriger rauszufinden sind wie:
>
> Jörg W. schrieb:
>> dass einem der Stack dann nicht in die
>> globalen bzw. statischen Variablen reinrennt
>
> nämlich Speicherleaks und Fragmentierung.

Einfacher?  Sorry.  Eine durch den Stack zerschossene globale
Variable zu finden, dürfte so ziemlich zu den übelsten Übungen
gehören, die man als Programmierer eines Mikrocontrollers zu lösen
hat. In aller Regel hast du dann, wenn du das Übel bemerkst,
keinerlei Idee mehr, wann das Problem aufgetreten sein könnte.
(Wenn man einen Debugger hat, der Daten-Breakpoints sezten kann,
ist man natürlich klar im Vorteil.)

Dagegen ist eine von malloc() geworfene 0 ja himmlisch einfach zu
debuggen.  Auch die Fragmentierung kann man, wenn man es möchte,
gelegentlich verifizieren (zumindest im Debugger), denn bei der
avr-libc ist der Quellcode offengelegt, sodass man sich dessen interne
Datenstrukturen ansehen kann.  BTDT.

Fragmentierung ist ohnehin ein eher künstlich aufgebauschtes Problem,
sofern man 1) tatsächlich statistisch gut verteilte Eingabedaten
hat und 2) einigermaßen Reserve beim Speicher.  Die nötige Reserve
fällt aber (wiederum: bei Daten mit tatsächlich dynamischer Größe)
immer noch drastisch geringer aus als das, was man benötigt, wenn
man alles in statischen Arrays ablegen möchte.  Beispiel: du
bekommst im Laufe der Zeit Anforderungen für 3, 20, 14, 110 und
42 Bytes.  Bei statischer Allozierung brauchst du 550 Bytes, um 5
Telegramme von maximal 110 Byte abzulegen.  Bei dynamischer Allozierung
brauchst du (auf AVR bezogen) 197 Bytes.  Gegenüber den 550 Bytes hast
du jetzt mehr als 100 % Reserve.  In dieser Reserve bekommst du auch
für den pathologischen Fall, dass der 110er Block erst als letztes
wieder freigegeben wird, problemlos noch viel mehr Daten unter.

> Siehe das Beispiel des TOs.

Er hat rundum so viele Anfänger-Fehler, die kannst du nun nicht einem
malloc() anlasten.

: Bearbeitet durch Moderator
von Jan H. (janiiix3)


Lesenswert?

Jörg W. schrieb:
> Er hat rundum so viele Anfänger-Fehler, die kannst du nun nicht einem
> malloc() anlasten.

Welche?

von Marco H. (damarco)


Lesenswert?

Das man im Code nicht durchsieht und somit die Gefahr von Leaks sehr 
groß ist.
Auch das malloc in dem besagten Code wenig Sinn macht. Zumal dieser 
richtig viele Fallen enthält. Ich rate er sich mit dem Thema Pointer und 
Strings sich zu beschäftigen.

Auf einen AVR funktioniert der Quark natürlich, ein ARM zieht die 
Reißleine. Oder der ESP löst den Schleudersitz aus -> Reset.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Marco H. schrieb:
> Auf einen AVR funktioniert der Quark natürlich

Beim TE selbst da eben nicht.

von avr (Gast)


Lesenswert?

Rolf M. schrieb:
> Auf dem PC schon, aber auf einem kleinen 8-Bitter nicht.

Die Welt besteht nicht nur aus kleinen 8bittern. Außerdem vermute ich, 
dass die malloc Implementierung auf avrs oder Arms nicht nicht gleich 
ein paar 10 Bytes benötigt wie auf dem PC.

Rolf M. schrieb:
> Wie kommst du darauf? Vom Hörensagen, oder hast du das getestet?

Ich hätte von dir eigentlich was qualifizierteres erwartet. Folgendes 
Szenario: es werden fifos unterschiedlicher Größe in einer Klasse 
benötigt.

fifo_create(n) gibt ein fifo mit n Elementen zurück.
1
Class foo{
2
  fifo* f;
3
  foo(int n){
4
    f = fifo_create<int>(n);
5
  }
6
}

Ein Template parameter für n führt zu einem weiteren in foo, wodurch für 
jede fifogröße neuer Code für foo und fifo angelegt wird. Das einzige 
was mir noch einfällt ist, dass man die Funktionalität von foo in einer 
Basisklasse implementieren kann. Kleiner und übersichtlicherer wird das 
aber sicher auch nicht.

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


Lesenswert?

avr schrieb:
> Außerdem vermute ich, dass die malloc Implementierung auf avrs oder Arms
> nicht nicht gleich ein paar 10 Bytes benötigt wie auf dem PC.

ARM benutzt newlib, das könnte schon ein bisschen größer ausfallen.

avr-libc benutzt eine eigene Variante, die hat zwei Byte (ein Zeiger)
Overhead pro Allokation, zuzüglich einiger weniger globaler Variablen.

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.