Seite 1 von 3
Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 00:35
von Serpens66
Hi
Worauf muss ich achten, wenn ich ein Python Skript unendlich lange in einem Loop laufen lassen will, damit nicht zuviel Arbeitsspeicher verbraucht wird? Ich habe nämlich das Problem, dass nach ca. 2-3 Tagen, mein gegebener Arbeitsspeicher von 512MB (ein Droplet auf digitalocean), voll ist und dadurch mein Skript beendet wird.
Wie immer ist mein Skript unglaublich lang und umfangreich und mein Erstlingswerk, also absolut mies geschrieben. Aber natürlich wird überall hier und da geflickt und verbessert, damit es iwann mal kein mieser Code mehr ist. Nun ist also das Arbeitsspeicher Problem dran.
Kurz zusammengefasst erstellt und verwendet mein Skript viele Dictionaries und Listen. Außerdem gibt es viele print()'s aus und schreibt die wichtigsten Meldungen in txt Dateien mithilfe von:
Code: Alles auswählen
with open('History.txt', 'a') as f :
f.write("%s" % text)
Erwähnenswert ist noch, dass ich mein
Skript in Form eines Services laufen lassen.
D.h mit "service MeinSkript start" starte ich es und mit "journalctl -u MeinSkript --since..." frage ich einige prints ab.
Die Dauerschleife dauert ungefähr 10 sekunden. Die meisten dictionaries sind in self. Form und werden zu Beginn einmal leer erstellt. In jedem Durchlauf sollen sie wieder verwendet werden und einzelne Werte darin aktualisiert werden. dazu schreibe ich dann einfach sowas wie self.beispieldict[essen] = 3 usw. Natürlich verwende ich innerhalb von definitionen auch listen und dictionaries ohne self. , aber ich glaube die sollten kein Problem sein, da sie nach Beenden der definition ja wieder gelöscht werden, oder?
Nun frage ich mich, warum soviel Arbeitsspeicher verbraucht wird. Liegt es daran, dass es als service läuft (das journal beinhaltet irgendwann ja ziemlich viele prints)? Oder an den self. Variablen, obwohl diese ja wiederverwertet werden? Oder daran, dass das Schreiben in eine txt Datei nicht richtig gemacht wird?
Ich denke wir probieren es erstmal mit dem journal.
Wie könnte ich die im journal gespeicherten prints via skript löschen?
PS: Das Forum scheint seit ein paar Monaten ein neues Design zu haben, aber in allen alten Beiträgen werden dadurch die Python Codes nicht mehr schön angezeigt, da steht nur noch code=python file=Untitled.py, anstatt dass es richtig formatiert wird. Wird das noch irgendwann gefixt oder bleiben alte Beiträge nun unübersichtlich? (wurde sicher schonmal iwo angesprochen, aber es wundert mich schon sehr, dass es nach sovielen monaten noch immer nicht verbessert wurde O.ô )
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 00:41
von snafu
Du müsstest uns schon konkreten Code zeigen. Gerne auch über ein externes Pastebin. So ganz allgemein würde ich sagen, dass du in der Schleife ständig neue Objekte anhängst und diese irgendwann den Speicher sprengen. Du müsstest insofern veraltete Objekte abräumen. Das geht entweder explizit mittels `del` oder – und viel häufiger anzutreffen – über eine Implementierung, die so programmiert ist, dass nicht mehr benötigte Objekte durch neue Objekte ersetzt werden. Wie gesagt: Konkreter kann man erst werden, wenn du den tatsächlich verwendeten Code zeigst.
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 00:46
von Serpens66
snafu hat geschrieben:Du müsstest uns schon konkreten Code zeigen. Gerne auch über ein externes Pastebin. So ganz allgemein würde ich sagen, dass du in der Schleife ständig neue Objekte anhängst und diese irgendwann den Speicher sprengen. Du müsstest insofern veraltete Objekte abräumen. Das geht entweder explizit mittels `del` oder – und viel häufiger anzutreffen – über eine Implementierung, die so programmiert ist, dass nicht mehr benötigte Objekte durch neue Objekte ersetzt werden. Wie gesagt: Konkreter kann man erst werden, wenn du den tatsächlich verwendeten Code zeigst.
mein skript ist 14k Zeilen lang, ich wüsste nicht, welcher Abschnitt speziell interessant sein würde.
Deswegen brauch ich erstmal die Erklärung allgemein, wie ich denn dafür sorge, dass nicht mehr benötigte Objekte ersetzt werden. Bzw. ein Beispiel wie es eben nicht aussehen darf
Aber um uns viel Mühe zu ersparen, würde ich sagen gehen wir besser der Reihenfolge nach, was ich denke die hauptursache sein könnte.
Also wie sieht das mit dem journal aus ? Da sind ja dann viele viele prints drin, die ich abfragen kann. Das kann doch ein Arbeitspsiecher-fresser sein, oder? Wenn es via skript fürs erste zu kompliziert sein sollte, gibt es denn einen konsolen Befehl, den ich eintippen kann, um das journal eines services zu löschen? Dann sehe ich durch den "top" Befehl ja, ob der genutzte Arbeitsspeicher zurück geht, oder nicht
edit:
sehe gerade, dass im "top" befehl das journal explizit aufgelistet wird.
Kann mir jemand diese Ausgabe erklären? Es werden ja 468448 Bytes benutzt. Aber wo ergibt dieser Wert sich in der Tabelle?
Code: Alles auswählen
top - 00:40:01 up 6 days, 23:52, 1 user, load average: 0.15, 0.11, 0.14
Tasks: 59 total, 1 running, 58 sleeping, 0 stopped, 0 zombie
%Cpu(s): 86.7 us, 0.7 sy, 0.0 ni, 11.3 id, 0.0 wa, 0.0 hi, 0.0 si, 1.3 st
KiB Mem: 506340 total, 468448 used, 37892 free, 90172 buffers
KiB Swap: 0 total, 0 used, 0 free. 157988 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
15443 root 20 0 837800 171564 9128 S 87.8 33.9 123:11.86 python3.4
157 root 20 0 37424 4800 2400 S 0.7 0.9 19:41.42 systemd-jou+
1 root 20 0 28556 3940 2348 S 0.0 0.8 0:13.85 systemd
die Tabelle geht natürlich noch weiter, aber das sind jetzt die drei die oben stehen. Was muss ich addieren, um auf die 468448 zu kommen ?
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 00:53
von Dav1d
Eine Datei 14k Zeilen
Kannst dir mit
memory_profiler anschauen wo der memory herkommt. Wenn dir das nicht reicht gibts noch mehr
Memory-Profiler, z.T. auch web basiert.
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 08:45
von Sirius3
@Serpens66: schreiben in eine Datei braucht keinen Arbeitsspeicher und der Journal-Dienst ist nur für die Verteilung der Daten da und, da er vom Anbieter stammt, hat auch nur mit sehr geringer Wahrscheinlichkeit ein Speicherleck.
Der erste Schritt um das Problem zu lösen, ist, die 14k Datei in kleine logische Einheiten aufzuspalten. Wenn es sich immer um einen unabhängigen Durchlauf handelt, sorge dafür, dass Du keine Daten überschreibst, sondern jedes Mal neue Objekte erzeugst. Dictionaries mit leeren Einträgen zu erzeugen, ist auch eher ein Zeichen dafür, dass man nicht pythonisch programmiert.
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 11:49
von BlackJack
@Serpens66: Wenn man sauber programmiert ist das in der Regel schon der erste Schritt speicherschonend zu programmieren, weil dann kleine übersichtliche Teilaufgaben jeweils in einer eigenen Funktion erledigt werden, und nur lokal für diese Aufgabe benötigte Objekte auch nur so lange Speicher belegen müssen, wie die Funktion abläuft.
Ansonsten schliesse ich mich Sirius3 an: Wenn es geht, keine Datenstrukturen wiederverwenden die man wegwerfen könnte, denn dann muss man sich selber darum kümmern, dass sich da nicht irgendwo doch immer mehr Daten sammeln, weil man irgendwo vergessen hat welche explizit aus einer Datenstruktur zu entfernen. Wenn man alte Datenstrukturen verwirft und mit neuen Objekten anfängt, hat man diese Fehlerquelle zumindest reduziert.
Was man sonst noch machen könnte, wäre bei grösseren Datenmengen darauf achten das man „lazy“ programmiert, also wo es geht Iteratoren, Generatorfunktionen und -ausdrücke verwenden, um möglichst wenig Daten gleichzeitig im Speicher halten zu müssen.
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 20:43
von Serpens66
Das Betriebssystem ist übrigens Debian 8.1, hatte ich vergessen zu erwähnen ^^
Danke für die Tipps bisher.
Ich werde die Tage mal ein Beispiel schreiben, wie ich das mit dem leeren dictionary meine und mache. Dann könnt ihr ja scheiben, ob das so okay ist, oder falsch.
Allerdings habe ich eben auch nochmal den top Befehl eingegeben, während mein Skript nicht lief. Könnt ihr mir sagen, warum dennoch soviel Arbeitsspeicher verbraucht wird, oder sollte ich mich da an ein anderes Forum wenden, weil das nicht direkt mit Python zusammenhängt?
Code: Alles auswählen
top - 19:20:01 up 7 days, 18:32, 1 user, load average: 0.01, 0.10, 0.17
Tasks: 65 total, 1 running, 64 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.3 us, 0.3 sy, 0.0 ni, 98.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.7 st
KiB Mem: 506340 total, 331300 used, 175040 free, 61524 buffers
KiB Swap: 0 total, 0 used, 0 free. 208172 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
13018 root 20 0 82668 5948 5096 S 0.3 1.2 0:00.95 sshd
18633 root 20 0 23528 2796 2356 R 0.3 0.6 0:00.83 top
1 root 20 0 28556 3844 2252 S 0.0 0.8 0:14.87 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kthreadd
3 root 20 0 0 0 0 S 0.0 0.0 2:35.51 ksoftirqd/0
5 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kworker/0:0H
7 root 20 0 0 0 0 S 0.0 0.0 10:11.78 rcu_sched
8 root 20 0 0 0 0 S 0.0 0.0 0:00.00 rcu_bh
9 root rt 0 0 0 0 S 0.0 0.0 0:00.00 migration/0
10 root rt 0 0 0 0 S 0.0 0.0 0:15.97 watchdog/0
11 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 khelper
12 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kdevtmpfs
13 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 netns
14 root 20 0 0 0 0 S 0.0 0.0 0:00.56 khungtaskd
15 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 writeback
16 root 25 5 0 0 0 S 0.0 0.0 0:00.00 ksmd
17 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 crypto
18 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kintegrityd
19 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 bioset
20 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kblockd
22 root 20 0 0 0 0 S 0.0 0.0 0:09.40 kswapd0
23 root 20 0 0 0 0 S 0.0 0.0 0:00.00 fsnotify_mark
29 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kthrotld
30 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 ipv6_addrconf
31 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 deferwq
65 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 ata_sff
66 root 20 0 0 0 0 S 0.0 0.0 0:00.00 khubd
67 root 20 0 0 0 0 S 0.0 0.0 0:00.00 scsi_eh_0
68 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 scsi_tmf_0
70 root 20 0 0 0 0 S 0.0 0.0 0:00.00 scsi_eh_1
72 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 scsi_tmf_1
93 root 20 0 0 0 0 S 0.0 0.0 0:27.46 jbd2/vda1-8
94 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 ext4-rsv-conver
137 root 20 0 0 0 0 S 0.0 0.0 0:00.00 kauditd
157 root 20 0 37424 6680 4280 S 0.0 1.3 20:36.26 systemd-journal
161 root 20 0 40792 476 4 S 0.0 0.1 0:00.07 systemd-udevd
194 root 20 0 0 0 0 S 0.0 0.0 0:00.00 vballoon
196 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kpsmoused
271 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 kvm-irqfd-clean
448 root 20 0 37068 1740 1320 S 0.0 0.3 0:04.07 rpcbind
460 statd 20 0 37268 596 8 S 0.0 0.1 0:00.00 rpc.statd
476 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 rpciod
478 root 0 -20 0 0 0 S 0.0 0.0 0:00.00 nfsiod
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 21:12
von Dav1d
Das ist normal, siehe auch
free command.
Wobei sich mein 'free' schon geändert hat (in ein Format das weniger verwirrend ist):
Code: Alles auswählen
total used free shared buff/cache available
Mem: 15983 2523 9308 171 4152 13182
Swap: 0 0 0
Aber selbst hier kann man leicht sehen (btw das sind nicht bytes sonder MiB), dass used + free != total.
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 12. Januar 2016, 21:14
von BlackJack
@Serpens66: Wenn Du wissen möchtest was so den Speicher verbraucht, solltest Du Dir das nicht nach Prozessorauslastung sondern nach Speicherverbrauch sortieren lassen.
Re: Arbeitsspeicher sparend coden
Verfasst: Mittwoch 13. Januar 2016, 12:42
von Sr4l
Beim beobachten vom "free memory" musst du immer aufpassen ob das Tool, welches du verwendest die "buffer and caches" mitrechnet oder rausrechnet. Diese werden automatisch freigegeben wenn ein Programm Arbeitsspeicher benötigt.
Re: Arbeitsspeicher sparend coden
Verfasst: Donnerstag 14. Januar 2016, 22:00
von Serpens66
Sr4l hat geschrieben:Beim beobachten vom "free memory" musst du immer aufpassen ob das Tool, welches du verwendest die "buffer and caches" mitrechnet oder rausrechnet. Diese werden automatisch freigegeben wenn ein Programm Arbeitsspeicher benötigt.
ja stimmt, das stand auch im Link von Dav1d.
Wenn ich "free" eintippe, sehe ich, dass der Wert in der "-/+ buffers/cache" und "free" Spalte recht groß ist, zurzeit, nach kurzer Laufzeit des Services, 340900.
Das scheint ja schon ziemlich viel zu sein, was bei Bedraf freigegeben werden kann.
Merkwürdig nur, dass der Service schon 2 mal gekillt wurde, wenn ich es zu lange am Stück laufen lasse.
Ich könnte vermutlich besser testen, was genau der Auslöser ist, wenn ich sichergehen kann,
dass der Service nach dem Kill wieder neu gestartet wird.
Wisst ihr da zufällig, wie man das umsetzen kann?
Denn solange es nicht automatisch neu startet, traue ich mich nicht den Service länger laufen zu lassen, da es nicht gut, ist, wenn der Service nicht mehr läuft (besonders wenn es über Nacht passiert und ich es erst stunden später merke)
Re: Arbeitsspeicher sparend coden
Verfasst: Donnerstag 14. Januar 2016, 22:35
von BlackJack
@Serpens66: Um Prozesse zu überwachen und gegebenenfalls neu zu starten gibt es natürlich Lösungen. Klassisch so etwas wie daemontools oder supervisord. Bei Debian 8 a.k.a. Jessie kannst Du auch mal `systemd` anschauen, das wird da ja schon verwendet.
Re: Arbeitsspeicher sparend coden
Verfasst: Freitag 15. Januar 2016, 00:21
von Serpens66
BlackJack hat geschrieben:@Serpens66: Um Prozesse zu überwachen und gegebenenfalls neu zu starten gibt es natürlich Lösungen. Klassisch so etwas wie daemontools oder supervisord. Bei Debian 8 a.k.a. Jessie kannst Du auch mal `systemd` anschauen, das wird da ja schon verwendet.
hast du ein paar stichworte nach denen ich suchen könnte?
Wenn ich nach "jessie systemd service automatisch starten" suche, kommen in erster Linie ergebnisse, wie man services nach einem system neustart/crash automatisch startet. Aber ich suche ja eine automatischen Neustart, nachdem der Service gekilled wurde.
und "jessie systemd service restart after kill" bringt dieselben ergebnisse... =/
edit:
oder decken die "runlevel" das zufällig auch mit ab?
https://www.digitalocean.com/community/ ... l-examples
Re: Arbeitsspeicher sparend coden
Verfasst: Freitag 15. Januar 2016, 00:49
von Dav1d
Ich persönlich würds mit supervisor machen, richtig gutes Tool, benutze ich für fast alles: Websites, andere Netzwerk-Services, Daemons etc.
Bei solchen sachen wirst du auf Deutsch nicht fündig: 'systemd service auto restart' ->
http://www.freedesktop.org/software/sys ... rvice.html (und Ctrl+F restart), btw. man kann auch in der manpage auf dem RPI nachschauen

.
Trotzdem würde ich dir empfehlen mal supervisord anzuschauen.
Re: Arbeitsspeicher sparend coden
Verfasst: Freitag 15. Januar 2016, 01:06
von BlackJack
@Serpens66: Die
systemd.service-Manpage beispielsweise. ``Restart=`` ist da eine relevante Option.
Re: Arbeitsspeicher sparend coden
Verfasst: Freitag 15. Januar 2016, 18:29
von Serpens66
Dav1d hat geschrieben:Ich persönlich würds mit supervisor machen, richtig gutes Tool, benutze ich für fast alles: Websites, andere Netzwerk-Services, Daemons etc.
Bei solchen sachen wirst du auf Deutsch nicht fündig: 'systemd service auto restart' ->
http://www.freedesktop.org/software/sys ... rvice.html (und Ctrl+F restart), btw. man kann auch in der manpage auf dem RPI nachschauen

.
Trotzdem würde ich dir empfehlen mal supervisord anzuschauen.
habe mir supervisor mal hier durchgelesen:
https://www.digitalocean.com/community/ ... debian-vps
Hab ich das richtig verstanden, dass dies eine Alternative ist, zum Service? Also ich würde das Skript dann nicht so wie jetzt, als Service laufen lassen, sondern eben mit dem supervisor?
Mit der Restart Möglichkeit bei einem "unexpected" Fehler klingt das aufjedenfall gut. Danke
Mal schauen, wann ich dafür Zeit habe. Ich befürchte, dass das einige Stunden dauern wird, das einzurichten. In der Regel gibts bei sowas oft Probleme mit der directory

Also wo ich das Skript und die dazugehörigen Dateien und Skripte hinpacken muss, damit der Zugriff einwandfrei funktioniert. Auch sehe ich im Tutorial noch keine Möglichkeit, die Größe der logs zu verringern... muss ich dann auch noch raussuchen ^^
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 9. Februar 2016, 15:59
von Serpens66
Habe einen Weg gefunden, bei dem der Service nie wegen zu wenig arbeitsspeicher gekilled wird.
Es scheint tatsächlich hieran zu liegen:
Code: Alles auswählen
with open('History.txt', 'a') as f :
f.write("%s" % text)
Denn wenn ich täglich die vom Vortag angelegte .txt Datei lösche, kann das Skript problemlos tagelang durchlaufen.
Lösche ich die .txt Datei allerdings nicht, sodass sie zu groß wird, wird der service irgendwann gekilled.
Vllt liegt das daran, dass bei jedem öffnen der datei der gesamte inhalt im arbeitspeicher geöffnet wird?
Falls ja, gibt es eine bessere Art der Öffnung einer txt Datei, um nur untendran etwas hinzuzufügen? Dafür muss ja der ganze kram der vorher geschrieben wurde nicht mit geöffnet werde.
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 9. Februar 2016, 16:15
von Sirius3
@Serpens66: nein, die Datei landet nicht im Arbeitsspeicher. Kann es sein, dass es gar nicht am Arbeitsspeicher liegt, sondern dass Deine Disk-Quota überschritten wird?
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 9. Februar 2016, 16:38
von Serpens66
Sirius3 hat geschrieben:@Serpens66: nein, die Datei landet nicht im Arbeitsspeicher. Kann es sein, dass es gar nicht am Arbeitsspeicher liegt, sondern dass Deine Disk-Quota überschritten wird?
Der digitalocean support meinte damals, ich solle "sudo cat /var/log/messages" ausführen und ihm das ergebnis schicken. Hatte ich gemacht und er schrieb daraufhin:
Dec 23 21:57:26 MeinServer kernel: [4790455.532401] python3.4 invoked oom-killer: gfp_mask=0x280da, order=0, oom_score_adj=0
This means that your Droplet is running out of memory which is causing processes to be killed. You will need to figure out what is using so much memory (it could be your python program) to prevent this from happening.
Ich nutze den 5 $/monat Plan
https://www.digitalocean.com/pricing/ , also sollte ich doch 20GB freien Speicher haben. Und "memory" heißt doch arbeitsspeicher, oder?
Die textdateien werden schon recht groß. Aktuell lösche ich sie wenn sie ungefähr 500 MB groß sind. Weiß nicht was genau die Schwelle ist, bis der service gekilled wird... könnten 1 bis 2 GB sein. Aber 20 GB sind die txt dateien definitv nicht groß.
Aktuell wird mir folgendes angezeigt (die fragliche txt datei ist gerade nur 66 MB groß):
Code: Alles auswählen
root@MeinServer:~# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 20G 2.5G 17G 14% /
udev 10M 0 10M 0% /dev
tmpfs 99M 13M 87M 13% /run
tmpfs 248M 0 248M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 248M 0 248M 0% /sys/fs/cgroup
Re: Arbeitsspeicher sparend coden
Verfasst: Dienstag 9. Februar 2016, 17:28
von BlackJack
@Serpens66: An der Programmzeile kann es aber nicht liegen. Ausser Du speicherst die Datei nicht auf dem Massenspeicher sondern in den Arbeitsspeicher. Speicherst Du die Datei unterhalb irgendeines Pfades der beim ``df`` mit dem Typ `tmpfs` aufgelistet wird? Unter `/run/` beispielsweise?