Forum: Mikrocontroller und Digitale Elektronik string-Objekte auf dem Heap


von Verbatim (Gast)


Lesenswert?

Guten Tag,

ich setze hier einen MSP430 ein und arbeite mit string-Objekten. Bevor 
das "warum" kommt:

1.) Gibt der Controller/die Anwendung das her
2.) Muss ich wirklich viel mit Dateien und Verzeichnissen arbeiten, da 
ist die string-Klasse eine Erleichterung.

Jetzt das Problem:
------------------

Heap hatte ich auf 512 Bytes eingestellt.

Der Ablauf ist folgender: Ich baue mir aus der aktuellen Uhrzeit/dem 
aktuellen Datum jeweils den aktuellen Pfad zu den Dateien&Verzeichnissen 
zusammen und verwende dafür ein string-Objekt 'pathToFile'. Nach einer 
Weile hängt sich mein Programm auf. Und zwar genau wenn die nachfolgende 
erste Zeile mit dem "if" ins Spiel kommt:
1
if (pathToFile!= file.getPathToFile()) {
2
    /* Hier ist alles auskommentiert, theoretisch würde jetzt aber die alte Datei geschlossen und eine neue geöffnet werden. */
3
}
4
5
// Das macht 'getPathToFile'
6
const string& getPathToFile() const {
7
  return m_pathToFile;
8
}

Kommentiere ich diese if-Bedingung aus, dann läuft das Programm, ist der 
Abgleich drinne knallt es nach ein paar Sekunden.

Erhöhe ich jetzt den Heap von 512 auf 768 Bytes, dann scheint die 
Anwendung korrekt zu laufen. Hier verstehe ich den Hintergrund nicht. 
Meine Vermutung war das der Destruktor des strings zwar Heap-Speicher 
freigibt, dieser aber fragmentiert wird und es deswegen igendwann 
knallt.

Dagegen spricht, dass es mit 768 Bytes endlos läuft. Dagegen spricht 
auch, das das Programm nicht abstürzt, wenn die if-Bedingung nicht 
ausgeführt wird, obwohl hier laufend string-Objekte angelegt und 
zerstört werden.

Was kann das sein?

von Karl H. (kbuchegg)


Lesenswert?

Verbatim schrieb:

> Meine Vermutung war das der Destruktor des strings zwar Heap-Speicher
> freigibt, dieser aber fragmentiert wird und es deswegen igendwann
> knallt.

Klingt als Hypothese nicht schlecht

> Dagegen spricht, dass es mit 768 Bytes endlos läuft.

Wieso soll das dagegen sprechen?
Wenn immer wieder sich Lücken auftun, die groß genug sind, dann kann das 
ewig so weiter gehen.
Das Problem bei Fragmentierung ist, dass man sehr genau analysieren 
müsste, wann welcher Speicher belegt und wann welcher Speicher frei 
gegeben wird und wann kleinere nebeneinander liegende freie 
Speicherbereiche wieder zu einem größeren zusammengefügt werden.

von Holger S. (holger_s30)


Lesenswert?


von Verbatim (Gast)


Lesenswert?

Aber spricht nicht gegen die Hypothese, dass das Programm nur dann 
abstürzt, wenn diese Zeile enthalten ist:
1
if (pathToFile!= file.getPathToFile())


? Oder wird hier tatsächlich auch Speicher angefordert, das ist doch ein 
simpler Vergleich?


Gibt es Faustregeln wie groß der Heap sein sollte, oder ist das eine 
Gefühlssache? Ich meine wie kann ich jetzt davon ausgehen, dass es ewig 
mit 768 Bytes korrekt läuft?

von Verbatim (Gast)


Lesenswert?

Holger S. schrieb:
> http://www.cplusplus.com/reference/string/string/compare/

Inwiefern hilft das? Ist die interne Implementierung von compare anders 
als der != operator?

von Mark B. (markbrandis)


Lesenswert?

Holger S. schrieb:
> http://www.cplusplus.com/reference/string/string/compare/

Eben, seit wann vergleicht man Strings mit == und != ?

Ah so,  mit C++ verwechselt. Wenn == und != korrekt überladen sind, dann 
geht das so.

von Verbatim (Gast)


Lesenswert?

Mark Brandis schrieb:
> Holger S. schrieb:
>> http://www.cplusplus.com/reference/string/string/compare/
>
> Eben, seit wann vergleicht man Strings mit == und != ?


Wollt ihr mich auf den Arm nehmen? Erstens ist '==' der gängige Weg und 
zweitens habe ich nachgeschaut wie das bei meiner Bibliothek gemacht 
wird:

1
inline bool operator==(const string& _Left, const string& _Right)
2
{       // test for string equality
3
  return (_Left.compare(_Right) == 0);
4
}

Oha na sie mal an, ist ja dasselbe. Vielleicht habe ich auch nur die 
Ironie nicht verstanden.

von Holger S. (holger_s30)


Lesenswert?

Ruhig Blut. Erstmal solltest du vielleicht überlegen ob dein 
"Dateiansatz" auf einem MSP430 wirklich gebräuchlich ist.

Vielleicht erhälst du bei Einblick in den Assembler-Code einen Wink auf 
das Bottle-Neck.

von Mark B. (markbrandis)


Lesenswert?

Was passiert wenn man testweise den String mal nicht auf dem Heap, 
sondern:
-auf dem Stack anlegt (sofern aufgrund des Scopes möglich)?
-als globale Variable (evtl. globales char-Array mit fester Länge) 
anlegt?

von Verbatim (Gast)


Lesenswert?

Mark Brandis schrieb:
> Was passiert wenn man testweise den String mal nicht auf dem Heap,
> sondern:
> -auf dem Stack anlegt (sofern aufgrund des Scopes möglich)?
> -als globale Variable (globales char-Array mit fester Länge) anlegt?


Der string sorgt ja intern dafür, dass Speicher angefordert wird, ich 
selber lege den string ja auf dem stack an (also kein new).

Die globale Variable mit char-Array wäre meine Notfalllösung, falls das 
mit den strings zu unvorherseh bist.

Daher meine Frage: Wie bestimmte ich den Heapspeicher für eine 
Anwendung? Gibt es da Richtlinien? Ich habe schon recherchiert, aber der 
einzige Ansatz den ich gefunden habe besteht darin, experimentell 
herauszufinden, wann der Heap & Stack groß genug ist

von Verbatim (Gast)


Lesenswert?

Um mich mal selber zu zitieren:

Verbatim schrieb:
> Daher meine Frage: Wie bestimmte ich den Heapspeicher für eine
> Anwendung? Gibt es da Richtlinien? Ich habe schon recherchiert, aber der
> einzige Ansatz den ich gefunden habe besteht darin, experimentell
> herauszufinden, wann der Heap & Stack groß genug ist

Ich habe da soeben von IAR eine sehr gute Präsentation gefunden:
1
The first question to be answered when considering an application
2
using dynamic memory is how much heap do I need?
3
4
- This is really more of an estimate than a
5
determination

und
1
It is difficult to estimate how much heap space you will need
2
without some sort of tool to help analyze your dynamic
3
memory needs.
4
5
- There exist such tools for desktop Java (HAT, Heap Analysis Tool)
6
7
- No such tool as yet for Embedded C/C++

Aus: 
http://www.iar.com/Global/Resources/Seminars/Working_with_the_Stack_and_Heap.pdf


Ist wohl tatsächlich eine Schätzung.

von Andreas B. (andreasb)


Lesenswert?

Verbatim schrieb:
> Mark Brandis schrieb:
> Die globale Variable mit char-Array wäre meine Notfalllösung, falls das
> mit den strings zu unvorherseh bist.
>
> Daher meine Frage: Wie bestimmte ich den Heapspeicher für eine
> Anwendung? Gibt es da Richtlinien? Ich habe schon recherchiert, aber der
> einzige Ansatz den ich gefunden habe besteht darin, experimentell
> herauszufinden, wann der Heap & Stack groß genug ist

Wenn deine Applikation genug klein ist kannst du den Speicherverbrauch 
berechnen, also wenn du weisst du hast max. 3 Strings der länge X, Y und 
Z, dann speicher für Daten und Speicher für String Objekt berechnen.
(C++ compiler kann dir ggf. noch mit sizeof(string) etwas weiterhelfen)

Ich würde schätzen bevorzugen;-)

Es gibt aber noch eine andere Möglichkeit, ich weiss aber nicht ob das 
auf deinem µC umsetzbar ist, habe sowas noch nie im Mikrocontroller 
bereich gemacht.

new und delete überladen, bzw schauen ob du dich irgendwie reinhängen 
kannst. Dann kannst du feststellen wie viel Speicher das gebraucht wird, 
und ggf. wie gross die Blöcke sind.

Aber auch da bist du nur dann sicher wenn du immer die gleichen Daten 
zum verarbeiten hast, also wenn z.B. plötzlich doppelt so lange Strings 
von irgendwoher gelesen werden wird natürlich auch meh Speicher 
gebraucht, du müsstest also mit dem worst-case testen.


mfg Andreas

von Markus M. (mark_m)


Lesenswert?

Beim Datentype String musst Du aufpassen. Ist ein String einmal 
angelegt, ist dieser nicht mehr änderbar. Jede Änderung erzeugt eine 
Kopie des String auf dem Heap. Da kann der schnell mal überlaufen. Auf 
dem PC ist das, bis auf die Performance, kein Problem. Auf dem 
Controller schon.

Grüsse

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.