Forum: Mikrocontroller und Digitale Elektronik Stringarray allokieren und deallokieren


von Michael (k-mte)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe auf einem Raspberry Pi Speicher für einen mehrseitigen Text 
allokiert und deallokiert. Das Ergebnis habe ich mit /proc/mem in der 
Erwartung überprüft, dass der zur Verfügung stehende Speicherplatz beim 
Allokieren um einen gewissen Betrag weniger und beim Deallokieren wieder 
mehr geworden ist. Nach einem kompletten Zyklus von Allokieren und 
Deallokieren habe ich eigentlich erwartet, wieder auf demselben Betrag 
an freiem Speicher rauskommen, mit dem ich angefangen habe. Leider ist 
dem nicht so. Das von /proc/mem angezeigte scheint eher zufällig zu sein 
und in keinem Kausalzusammenhang mit meinem Allokieren / Deallokieren zu 
stehen. Was mache ich falsch?

: Bearbeitet durch User
von Jens G. (jensig)


Lesenswert?

Michael schrieb:
> dem nicht so. Das von /proc/mem angezeigte scheint eher zufällig zu sein

/proc/mem ist wohl daselbe wie /proc/meminfo auf einem Ubuntu-System. 
Und damit vermisst Du leider global das Gesamtsystem, und nicht nur das, 
was Dein Programm macht. Da spuckt Dir also alles mögliche in die Suppe, 
was auf dem Ding läuft ...
Du musst also /proc/<pid>/mem auslesen, damit Du nur Deinen Prozess 
siehst ...

Edit: /proc/<pid>/mem scheint bei mir nix auszugeben. Naja, muss man 
wohl doch anders abfragen. Z.B. "ps aux" -> VSZ ...

: Bearbeitet durch User
von Norbert (der_norbert)


Lesenswert?

man 5 proc_pid_statm
man 5 proc_pid_status
könnten helfen.
Edit:
Man darf auch direkt im Programm ausgeben, ohne externe tools.
1
#!/usr/bin/python3
2
# vim: fileencoding=utf-8: ts=4: sw=4: expandtab:
3
import os
4
with open(f'/proc/{os.getpid()}/status') as fr:
5
    for line in fr.readlines():
6
        print(line,end='')

: Bearbeitet durch User
von G. K. (zumsel)


Lesenswert?


von Rolf M. (rmagnus)


Lesenswert?

Norbert schrieb:
> Man darf auch direkt im Programm ausgeben, ohne externe
> tools.#!/usr/bin/python3
> # vim: fileencoding=utf-8: ts=4: sw=4: expandtab:
> import os
> with open(f'/proc/{os.getpid()}/status') as fr:
>     for line in fr.readlines():
>         print(line,end='')

Wenn der Prozess das für sich selbst macht,  muss er nicht mal die PID 
angeben. Einfach /proc/self nehmen. Das ist ein Symlink auf die aktuelle 
PID.

von Norbert (der_norbert)


Lesenswert?

Rolf M. schrieb:
> Wenn der Prozess das für sich selbst macht,

Stimmt. Wäre dann noch einmal kürzer:
1
#!/usr/bin/python3
2
# vim: fileencoding=utf-8: ts=4: sw=4: expandtab:
3
with open(f'/proc/self/status') as fr:
4
    print(*fr.readlines())

von Ein T. (ein_typ)


Lesenswert?

Michael schrieb:
> Was mache ich falsch?

Du glaubst, Linux' Speicherverwaltung sei einfach und linear. Das ist 
jedoch nicht der Fall. In der Realität macht der Kernel dabei ein paar 
sehr schlaue Dinge, und nicht einmal ein malloc(3) tut genau das was wir 
gerne glauben -- Stichwort "Overcommit". Einen Überblick über die 
meisten Konzepte findest Du hier [1], mehr Details hier [2], und eine 
noch ausführlichere Darstellung im Verzeichnis Documentation/mm/ des 
Linux Kernel Sourcecode sowie hier [3].

[1] https://docs.kernel.org/admin-guide/mm/concepts.html
[2] https://tldp.org/LDP/tlk/mm/memory.html
[3] https://docs.kernel.org/mm/index.html

von Michael (k-mte)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe "man 5 proc_pid_statm" und "man 5 proc_pid_status" gelesen. 
Dort steht was von ungenau. Wenn man es genauer wissen möchte, soll man 
in "/proc/pid/smaps" nachschauen. Das habe ich (ohne system () zu 
benutzen) getan und die mit heap überschriebenen Abschnitte 
herauskopiert, siehe beigefügte Datei. Kann ich dieser entnehmen, dass 
meine Deallokation nicht stattfindet?

Abgesehen davon:

Hinter meiner Frage nach dem Heap-Verbrauch meines Programmes steht 
eigentlich die Frage, ob meine Funktionen zum Allokieren und 
Deallokieren meines Stringarrays funktionieren. Tun sie das?

Was brk () betrifft, so steht in "man 2 brk" in den Notizen: "Avoid 
using brk() and sbrk(): the malloc(3) memory allocation package is the 
portable and comfortable way of allocating memory." Da ich von brk () 
noch nie etwas gehört habe und momentan mit malloc und free eh schon 
alle Hände voll zu tun habe, würde ich gerne zumindest vorübergehend auf 
den Einsatz von brk () verzichten.

von Michael (k-mte)


Lesenswert?

Ein T. schrieb:
> Du glaubst, Linux' Speicherverwaltung sei einfach und linear. Das ist
> jedoch nicht der Fall.

Im Vergleich zu den 8 Bit-Microcontrollern, die ich üblicherweise ohne 
Betriebssystem nutze, gerne auch mal in Assembler, scheint Linux 
teilweise doch ein bischen komplizierter... ;-)

: Bearbeitet durch User
von Nemopuk (nemopuk)


Lesenswert?

Due Einführung einer neuen Programmiersprache war bei uns der Anlass, 
etwas genauer auf den Speicherbedarf unserer PODs zu achten. Es stellte 
sich heraus, dass er bei jeder Lastspitze etwas größer wurde und erst 
nach etwa 6 Wochen Laufzeit ein stabiles Niveau erreicht.

Wir hatten damals sehr viel Arbeitszeit und auch Geld für Tools 
aufgebracht, um das befürchtete Memory Leck zu finden. Aber da war 
keins. Das Zusammenspiel zwischen Garbage Collector, Kubernetes und 
Linux ist kaum noch zu durchschauen.

von Rolf M. (rmagnus)


Lesenswert?

Michael schrieb:
> Was brk () betrifft, so steht in "man 2 brk" in den Notizen: "Avoid
> using brk() and sbrk(): the malloc(3) memory allocation package is the
> portable and comfortable way of allocating memory."

malloc() nutzt intern selbst brk()/sbrk(), um Speicher vom System zu 
bekommen (oder alternativ bei großen Blöcken auch mmap()). Daher ist das 
Verhalten dieser Funktionen in dem Fall auch bei Nutzung von malloc() 
relevant.
Bedenke, dass Speicher vom System nicht byteweise, sondern nur in ganzen 
Speicherseiten verwaltet wird. malloc() kümmert sich dann innerhalb 
deines Prozesses um die feingranulare Allokation. Das heißt, dass 
Speicher nur dann überhaupt an das System zurückgegeben werden kann, 
wenn eine Speicherseite komplett frei wird. Dazu kommt, dass man mit 
brk()/sbrk() ja das Ende des Heap verschiebt. Damit kann natürlich 
prinzipbedingt nur Speicher zurückgegeben werden, der auch ganz am Ende 
des Heap liegt und nicht irgendwo mitten drin. Deshalb wird in der Regel 
Speicher, der per brk()/sbrk() allokiert wird, beim Freigeben zwar 
intern für das Programm wieder für neue Allokationen verfügbar gemacht, 
aber nicht komplett an das Betriebssytem zurückgegeben.

von G. K. (zumsel)


Lesenswert?

Nemopuk schrieb:

> Wir hatten damals sehr viel Arbeitszeit und auch Geld für Tools
> aufgebracht, um das befürchtete Memory Leck zu finden. Aber da war
> keins. Das Zusammenspiel zwischen Garbage Collector, Kubernetes und
> Linux ist kaum noch zu durchschauen.

Schau nicht auf verfügbaren memory sondern auf commited memory.

: Bearbeitet durch User
von G. K. (zumsel)


Lesenswert?

Michael schrieb:
> Was brk () betrifft, so steht in "man 2 brk" in den Notizen: "Avoid
> using brk() and sbrk(): the malloc(3) memory allocation package is the
> portable and comfortable way of allocating memory." Da ich von brk ()
> noch nie etwas gehört habe und momentan mit malloc und free eh schon
> alle Hände voll zu tun habe, würde ich gerne zumindest vorübergehend auf
> den Einsatz von brk () verzichten.
1
Calling sbrk() with an increment of 0 can be used to find the
2
current location of the program break.
Und bedenke das Pages die noch nicht angefasst wurden lediglich 
reserviert sind. Direkt nach einem malloc(100GB) ist fast noch genauso 
viel Speicher verfügbar wie direkt vor dem malloc.

: Bearbeitet durch User
von G. K. (zumsel)


Lesenswert?

Jens G. schrieb:

> Edit: /proc/<pid>/mem scheint bei mir nix auszugeben. Naja, muss man
> wohl doch anders abfragen. Z.B. "ps aux" -> VSZ ...

RSS kommt dem "tatsächlichen" Speicherverbrauch eines Prozesses näher 
als VSZ.

von Ein T. (ein_typ)


Lesenswert?

Michael schrieb:
> Hinter meiner Frage nach dem Heap-Verbrauch meines Programmes steht
> eigentlich die Frage, ob meine Funktionen zum Allokieren und
> Deallokieren meines Stringarrays funktionieren. Tun sie das?

Zur Beantwortung gibt es ein großartiges Programm namens valgrind [1], 
das bereits in den Paketrepositories von Raspbian enthalten ist und 
deswegen nur von Dir installiert und benutzt werden muß. Hinweis: für 
eine ausführliche Ausgabe empfiehlt sich der Parameter 
"--leak-check=full", viel Erfolg!

[1] https://valgrind.org/

von Ein T. (ein_typ)


Lesenswert?

Michael schrieb:
> Im Vergleich zu den 8 Bit-Microcontrollern, die ich üblicherweise ohne
> Betriebssystem nutze, gerne auch mal in Assembler, scheint Linux
> teilweise doch ein bischen komplizierter... ;-)

Nur gaaanz geringfügig. :-)

von Ob S. (Firma: 1984now) (observer)


Lesenswert?

G. K. schrieb:

> Direkt nach einem malloc(100GB) ist fast noch genauso
> viel Speicher verfügbar wie direkt vor dem malloc.

Ganz genau so ist das bei virtueller Speicherverwaltung. Angefordert 
wird nicht etwa physischer Speicher, sondern nur Adressraum. Ob und wann 
der mit physischem Speicher "hinterlegt" wird, entscheidet das OS, 
jedenfalls wenn der Programmierer nichts anderes vorgibt.

Für bestimmte Zwecke ist es nämlich durchaus möglich, einen "commit" 
(also das Hinterlegen mit physischem Speicher) unmittelbar bei der 
Speicheranforderung zu erzwingen. Für "normalen" Speicherbedarf ist das 
aber absolut nicht sinnvoll, jedenfall nicht, wenn das Ziel ist, das 
Gesamtsystem möglichst effizient zu betreiben.

von Jens G. (jensig)


Lesenswert?

G. K. schrieb:
>> Edit: /proc/<pid>/mem scheint bei mir nix auszugeben. Naja, muss man
>> wohl doch anders abfragen. Z.B. "ps aux" -> VSZ ...
>
> RSS kommt dem "tatsächlichen" Speicherverbrauch eines Prozesses näher
> als VSZ.

Kommt drauf an, ob man den Speicher wissen will, der tatsächlich im RAM 
liegt, oder den Speicher, der im virtuellen Adressraum belegt wird, bzw. 
das Programm glaubt zu belegen.
Da der TO den Effekt von malloc() wissen will, was erstmal nur 
virtuellen Speicher vorreserviert, macht eigentlich nur VSZ Sinn zu 
beobachten, und nicht RSS, was aus Anwendersicht eher zufälligen 
Charakter hat.

: Bearbeitet durch User
von Michael (k-mte)


Lesenswert?

Ein T. schrieb:
> Zur Beantwortung gibt es ein großartiges Programm namens valgrind [1],

mike@PC6:~/Privat/geany/work$ valgrind --leak-check=full ./stringarray_2
==6007== Memcheck, a memory error detector
==6007== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==6007== Using Valgrind-3.24.0 and LibVEX; rerun with -h for copyright 
info
==6007== Command: ./stringarray_2
==6007==
Hello, world

==6007==
==6007== HEAP SUMMARY:
==6007==     in use at exit: 0 bytes in 0 blocks
==6007==   total heap usage: 1,012 allocs, 1,012 frees, 109,104 bytes 
allocated
==6007==
==6007== All heap blocks were freed -- no leaks are possible
==6007==
==6007== For lists of detected and suppressed errors, rerun with: -s
==6007== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

:-)

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.