Arbeitsspeicher sparend coden
@Serpens: `psutil.test()` sieht ganz gut aus wenn man die Daten von allen laufenden Prozessen als Text ausgeben möchte. Das ist a) ein bisschen viel und b) müsste man das wenn man es weiterverarbeiten möchte, zum Beispiel um Verläufe zu plotten, erst wieder parsen. Man möchte ja eigentlich lieber beispielsweise eine CSV-Datei mit den Werten erstellen, die man hinterher einfach auswerten kann.
Okay, also was stattdessen? Bei process.memory_info() bin ich mir nicht sicher, ob das ist was wir brauchen, da ich mit den Begriffen rss, vms usw nicht soviel anfangen kann. Ist es das?BlackJack hat geschrieben:@Serpens: `psutil.test()` sieht ganz gut aus wenn man die Daten von allen laufenden Prozessen als Text ausgeben möchte. Das ist a) ein bisschen viel und b) müsste man das wenn man es weiterverarbeiten möchte, zum Beispiel um Verläufe zu plotten, erst wieder parsen. Man möchte ja eigentlich lieber beispielsweise eine CSV-Datei mit den Werten erstellen, die man hinterher einfach auswerten kann.
- miracle173
- User
- Beiträge: 127
- Registriert: Samstag 6. Februar 2016, 00:28
HalloSerpens66 hat geschrieben: (...)
meinst du ein stumpfes übernehmen dieses debug_nice skriptes zusammen mit dem example auf Pastebin würde den zweck erfuellen? http://pastebin.com/USVw11bJ
Keine Ahnung,l möglicherweise, ich kenne das nicht.
Angenommen du hast eine Variable die als Wert eine Liste hat. Wenn du an diese Liste Werte anhängst und vergisst, die Liste am beginn jedes Schleifendurchlaufs zu leeren, dann wird diese Liste immer länger. Der Wert der Variablen, also die Liste, wird durch locals() ausgegeben. Wenn du also locals nach einem Schleifeendurchlauf ausgibst, wir die entstehende Datei immer grösser, da ja diese Liste immer länger wird. Wenn die Datei, in die du locals schreibts, immer grössert als die vorherige wird, dann hast du also eine Variable, deren Wert im Laufe derzeit immer grösser (besser: länger) wird. Dass ist dann dein Memory leak. Dieser Test ist ja schnell implementiert und darum habe ich dir das empfohlen.
Wenn es aber nicht der Wert einer Variablen ist, der immer grössert wird, dann wirst du das mit dieser Methode nicht finden. Keine Variable bedeuted, es ist etwas auf das Referenziert wird, z.b. ein Objekt.
Ich hab das noch das gefunden. Das schaut auf den ersten Blick ganz nützlich aus:
https://pythonhosted.org/Pympler/tutori ... orial.html
mfg miracle173
https://github.com/python-forum-de/Jump-N-Run-pydesw
https://github.com/python-forum-de/Jump-N-Run-pydesw
- miracle173
- User
- Beiträge: 127
- Registriert: Samstag 6. Februar 2016, 00:28
Der top Befehl zeigt dir an, wieviel Memory dem Prozess aktuell zugeordnet ist. Allerdings gibt ein Linux-Prozess angefordertes Memory erst dann ans Betriebssystem zurück, wenn er beendet wird. Das heißt, auch wenn das Python-Programm wieder Memory frei gibt, wird das nicht vom Prozeß ans Betriebssystem zurückgegeben. Aber es wird dann wiederverwemder, wenn das Python-Programm wieder mehr Memory braucht. Insofern stellt der aktuelle Memory-Verbrauch des Prozesses, der von top angezeigt wird dem Peak-Value des Memory-Verbrauch des Python Programms dar.Serpens66 hat geschrieben: (...)
Ich dachte eig , dass ich mit dem top befehl den aktuellen verbrauch sehen könnte. Wusste nicht, dass das nur ein peak ist.
(...)
mfg miracle173
https://github.com/python-forum-de/Jump-N-Run-pydesw
https://github.com/python-forum-de/Jump-N-Run-pydesw
@miracle173: ich danke dir für deine Antworten :
Pympler sieht ganz gut aus, besonders der teil hier: https://pythonhosted.org/Pympler/muppy.html#muppy
Ich koennte also alles paar stunden so eine summary erstellen lassen und damit schauen, was so passiert. Werde das wenn ich etwas Zeit habe mal einbauen. Melde mich dann wieder mit dem Ergebnis oder eventuellen Problemen
Pympler sieht ganz gut aus, besonders der teil hier: https://pythonhosted.org/Pympler/muppy.html#muppy
Ich koennte also alles paar stunden so eine summary erstellen lassen und damit schauen, was so passiert. Werde das wenn ich etwas Zeit habe mal einbauen. Melde mich dann wieder mit dem Ergebnis oder eventuellen Problemen

- miracle173
- User
- Beiträge: 127
- Registriert: Samstag 6. Februar 2016, 00:28
Möglicherweise ist das nicht mehr ganz richtig, da nicht nur der brk System-Call zum Anfordern von Memory verwendet werden kann, sondern auch mmap, und das erlaubt auch die Rückgabe ans Betriebssystem mit dem Call von munmap.miracle173 hat geschrieben: (...)
Allerdings gibt ein Linux-Prozess angefordertes Memory erst dann ans Betriebssystem zurück, wenn er beendet wird.
(...)
mfg miracle173
https://github.com/python-forum-de/Jump-N-Run-pydesw
https://github.com/python-forum-de/Jump-N-Run-pydesw
- miracle173
- User
- Beiträge: 127
- Registriert: Samstag 6. Februar 2016, 00:28
Da braucht man nicht unbedingt zusätzliche Python-Module installieren. Die Tools, die auf einem Linuxrechner vorhanden sind, reichen aus.BlackJack hat geschrieben:@Serpens66: Das `psutils`-Modul würde sich IMHO anbieten.
Entweder top im Batch-Modus
Code: Alles auswählen
$ top -b -p 1 -d 3
top - 00:10:59 up 4 days, 22:04, 8 users, load average: 14.23, 10.05, 7.98
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
Cpu(s): 15.8%us, 2.2%sy, 0.1%ni, 81.6%id, 0.0%wa, 0.0%hi, 0.2%si, 0.0%st
Mem: 264085904k total, 236958216k used, 27127688k free, 1114120k buffers
Swap: 25165820k total, 2392k used, 25163428k free, 87088412k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 19404 1596 1276 S 0.0 0.0 51:03.93 init
top - 00:11:02 up 4 days, 22:04, 8 users, load average: 14.45, 10.16, 8.03
Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie
Cpu(s): 41.3%us, 1.1%sy, 0.0%ni, 57.3%id, 0.0%wa, 0.0%hi, 0.2%si, 0.0%st
Mem: 264085904k total, 237189644k used, 26896260k free, 1114120k buffers
Swap: 25165820k total, 2392k used, 25163428k free, 87088520k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 19404 1596 1276 S 0.0 0.0 51:03.93 init
Code: Alles auswählen
ps aux|head -1; ps aux|grep /sbin/init|grep -v grep
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.7 0.0 19404 1596 ? Ss Mar15 51:04 /sbin/init
mfg miracle173
https://github.com/python-forum-de/Jump-N-Run-pydesw
https://github.com/python-forum-de/Jump-N-Run-pydesw
@miracle173: Ja klar, man kann auch alles als Bash-Skript schreiben und dann Python ganz weglassen. Wenn ich den Speicherverbrauch eines Python-Programms vom Programm selber aus überwachen möchte und die Wahl habe externe, plattformabhängige Prozesse zu starten oder ein Python-Modul zu verwenden, das zudem auch noch auf mehr als einer Plattform läuft, nehme ich jedenfalls lieber das Modul. Zumal der OP das wegen dem Memory Profiler ja wohl sowieso schon installiert hatte.
Hallo zusammen, da bin ich wieder...Serpens66 hat geschrieben:@miracle173: ich danke dir für deine Antworten :
Pympler sieht ganz gut aus, besonders der teil hier: https://pythonhosted.org/Pympler/muppy.html#muppy
Ich koennte also alles paar stunden so eine summary erstellen lassen und damit schauen, was so passiert. Werde das wenn ich etwas Zeit habe mal einbauen. Melde mich dann wieder mit dem Ergebnis oder eventuellen Problemen
Ich habe das Thema so lange ruhen lassen, weil ich nun wie zuvor irgendwo empfohlen wurde, einen automatischen restart in den service eingebaut habe. So wurde der Service also nach ~3 Tagen gekilled, aber sodort wieder neugestartet und das war für mich okay.
Doch nun würde ich das verusrachende Skript gerne 5 mal gleichzeitig mit unterschiedlichen Einstellungen laufen lassen (mithilfe von Multithread)
Dabei habe ich nun leider gemerkt, dass der Kill nun sogar schon nach ~4 Stunden erfolgt. Und das ist mir trotz Neustart doch etwas zu schnell..
Also habe ich jetzt Pympler probiert:
Ca. alle 5 minuten schreibt mein Skript die summary in eine txt Datei (self.memhistory ist für das schreiben in die Datei mit Datum verantwortlich):
Code: Alles auswählen
self.memhistory('\n'.join(summary.format_(summary.summarize(muppy.get_objects()))))
Code: Alles auswählen
types | # objects | total size
==================================== | =========== | ============
<class 'str | 103292 | 8.79 MB
<class 'list | 28184 | 4.78 MB
<class 'dict | 5762 | 4.33 MB
<class 'type | 725 | 739.23 KB
<class 'code | 4779 | 672.24 KB
<class 'float | 14536 | 340.69 KB
<class 'set | 403 | 169.66 KB
<class 'tuple | 1878 | 125.44 KB
<class 'weakref | 1418 | 110.78 KB
<class 'int | 3256 | 91.18 KB
<class 'wrapper_descriptor | 1146 | 89.53 KB
<class 'builtin_function_or_method | 1104 | 69.00 KB
<class 'method_descriptor | 957 | 67.29 KB
<class 'getset_descriptor | 790 | 55.55 KB
<class 'abc.ABCMeta | 51 | 48.95 KB
Nun also 2 Fragen:
1) Es könnte theoretisch ja noch ein ruckartiger anstieg sein, der nur im moment des Kills auftritt. Wie würde ich diesen am besten sichtbar machen? Ich könnte anstelle von alle 5 Minuten , alle 20 sekunden so eine summary machen und den "diff" Befehl von pympler verwenden. Nur weiß ich grad nicht, wie ich dabei dann prüfen kann " fals diff >= x" um einen starken anstieg festzustellen...
Aber würde das was bringen? Angenommen es ist wirklich ein Fehler, der in kürzester Zeit tonnenweise Speicher verbraucht, dann wird der wohl auftreten und sofort zum kill führen, ohne dass ich den memory verbrauch vorher checken könnte... ?!
2) Ich verwende, um das Skript in 5 Einstellungen gleichzeitig laufen zu lassen multithreads:
Code: Alles auswählen
class MainClass():
#...
def parallel(self,aufgabenliste):
threads = list(map(Multithread, aufgabenliste))
for thread in threads:
thread.start()
for thread in threads
thread.join()
return(list(thread.result for thread in threads))
class Multithread(threading.Thread):
def __init__(self, aufgabe=0):
if aufgabe:
threading.Thread.__init__(self)
self.aufgabe = aufgabe[0] #ist ja ein Tupel aus funktion und argumenten
self.argumente = aufgabe[1]
self.result = None
return
def run(self):
self.result = self.aufgabe(*self.argumente)
return
Die memory summary habe ich nur in einer dieser einstellungen erlaubt, weil ich davon ausgehe, dass es die memory vom gesmaten Skript, also auch den anderen 4 schleifen zeigt. Ist das richtig?
Könnte der Memory Verbrauch evlt auch mit der verwendung der Threads zu tun haben?
@Serpens66: wenn es kein kontinuierlicher Anstieg ist, dann hilft es, wie Du ja bereits vermutest, nichts, das Intervall zu kürzen. Wildes Herumraten, wie schon vor einem halben Jahr, hat Dich ja auch nicht weiter gebracht. Entweder Du identifizierst selbst Stellen, an denen potentiell viel Speicher verbraucht werden könnte (Speicher, der abhängig von einer Variable reserviert wird, while-Schleifen, die Listen erzeugen und möglicherweise die Abbruchbedingung nie erfüllt wird) und gibst genau dort passende Debugausgaben aus. Oder zeig einfach, was Du da versuchst, dann finden wir gemeinsam viel schneller die problematischen Stellen.
Dadurch, dass der Kill nun deutlich schneller vonstatten geht, erstaunlicherweise gerade sogar schon nach wenigen Minuten nachdem das Skript neu gestartet wurde, lässt es sich zumindest etwas leichter untersuchen...
In den allermeisten Fällen findet der Kill nicht mitten in meinem riesigen Skript statt, sondern an derselben überschaubaren Stelle, die aber eig kein Problem darstellen sollte, oder doch?
Und zwar läuft das komplette Skript ganz simpel in einer "while True" Dauerschleife:
Nachdem der service gekilled wurde, ist der letzte Eintrag in meiner history txt Datei lustigerweise meistens (90% der Fälle, die andern 10% konnte ich noch nicht genau identifizieren):
nach durchlauf vor memreport
Das wirft die Vermutung auf, dass memhistory die Ursache ist, was aber nicht sein kann, da der Kill ja auch ohne das auftritt. Aber möglicherweise beschleunigt es den Kill und man kann so vllt auf eine mögliche Ursache schließen? memhistory wird jedenfalls nicht mehr vollständig ausgeführt, in der .txt Datei steht zum zeitpunkt des kills keine info.
Einzige Vermutung die sich daraus nun ergibt, ist dass das dauernde öffnen und schreiben in txt Dateien Probleme machen kann?
In den allermeisten Fällen findet der Kill nicht mitten in meinem riesigen Skript statt, sondern an derselben überschaubaren Stelle, die aber eig kein Problem darstellen sollte, oder doch?
Und zwar läuft das komplette Skript ganz simpel in einer "while True" Dauerschleife:
Code: Alles auswählen
#!/usr/bin/python3.4
# coding: utf8
from pympler import summary, muppy
import requests
import json
from time import sleep
import logging
import time
import threading
import sys
import traceback
from random import randint
import math
from copy import deepcopy
from decimal import *
def uhrzeit():
return(time.asctime())
class MyMain:
def memhistory(self,text):
text = str(text)
textmituhrzeit = "{} ########################################\n".format(uhrzeit())+text+"\n" # ich weiß unnötig kompliziert
with open('MemHistory.txt', 'a') as f :
f.write("%s" % textmituhrzeit)
def vorsuchen(self):
memreporten = 20
while True:
self.history("vor neuem durchlauf",0,0,1) # self.history schreibt text in eine txt datei
# suchen() ist die fkt die in dauerschleife laufen soll. Ein Durchlauf dauert durch Verwendung von time.sleep mindesten 5.
ret = self.suchen() # wenn unwahr, weiter schleife. wenn wahr, beenden
self.history("nach durchlauf vor memreport",0,0,1)
if memreporten>=1: # ursprünglich 20
self.memhistory('\n'.join(summary.format_(summary.summarize(muppy.get_objects())))) # memory info in txt datei speichern
memreporten = 0
memreporten += 1
self.history("nach durchlauf und memreport",0,0,1)
if ret:
self.history("suchen fkt beenden",0,0,1)
return
if __name__ == '__main__':
My = MyMain()
try:
My.vorsuchen()
except Exception as err:
My.FehlerBeenden() # kontrolliertes beenden
raise err
sys.exit()
nach durchlauf vor memreport
Das wirft die Vermutung auf, dass memhistory die Ursache ist, was aber nicht sein kann, da der Kill ja auch ohne das auftritt. Aber möglicherweise beschleunigt es den Kill und man kann so vllt auf eine mögliche Ursache schließen? memhistory wird jedenfalls nicht mehr vollständig ausgeführt, in der .txt Datei steht zum zeitpunkt des kills keine info.
Einzige Vermutung die sich daraus nun ergibt, ist dass das dauernde öffnen und schreiben in txt Dateien Probleme machen kann?
Zuletzt geändert von Anonymous am Samstag 15. Oktober 2016, 09:22, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Ergänzung:
Nachdem ich den memhistory Teil auskommentiert habe, gab es bei gleicher konfiguration jetzt 8 stunden keinen kill mehr. Ich komme also zum "normal" Zustand zurück, wo es einige Stunden dauert. Mit dem memhistory Ding ging das ja innerhalb von Minuten O.ô.
Die eigentlich verursachende Stelle im Code habe ich noch nicht gefunden, werde aber weiter versuchen es einzugrenzen.
Dennoch denke ich, wäre es gut zu wissen, warum memhistory so unglaublich schnell die memory auslastet, ohne dass die memory summary irgendwelche Anzeichen dazu zeigt?! Eventuell ist das Problem dem wir auf der Spur sind ähnlich gelagert?
Nachdem ich den memhistory Teil auskommentiert habe, gab es bei gleicher konfiguration jetzt 8 stunden keinen kill mehr. Ich komme also zum "normal" Zustand zurück, wo es einige Stunden dauert. Mit dem memhistory Ding ging das ja innerhalb von Minuten O.ô.
Die eigentlich verursachende Stelle im Code habe ich noch nicht gefunden, werde aber weiter versuchen es einzugrenzen.
Dennoch denke ich, wäre es gut zu wissen, warum memhistory so unglaublich schnell die memory auslastet, ohne dass die memory summary irgendwelche Anzeichen dazu zeigt?! Eventuell ist das Problem dem wir auf der Spur sind ähnlich gelagert?
Hallo Serpens66,
vielleicht solltest du mal damit anfangen, dass du dein Script aufräumst. Beispiel:
Die acht Zeilen, die du brauchst könntest du durch diesen Dreizeiler hier ersetzen(Bitte nicht in die Klasse packen, ist unnötig!):
Du kannst deinen Code leserlicher gestalten, indem du ihm eindeutige Namen gibst und auf dein deutsch/englisch Mischmasch verzichtest. Versuche deinen Code einheitlich zu gestalten(z. B. nicht immer zwischen " " und ' ' zu wechseln). Halte dich an den Style Guide for Python Code(CamelCase nur bei Klassen, Variablen etc. mit _).
Wenn du so viele Dateizugriffe hast und dort den Fehler vermutest, würde es dir vielleicht helfen auf eine Datenbank zurück zu greifen.
vielleicht solltest du mal damit anfangen, dass du dein Script aufräumst. Beispiel:
Code: Alles auswählen
def uhrzeit():
return (time.asctime())
def memhistory(self, text):
text = str(text)
textmituhrzeit = "{} ########################################\n".format(
uhrzeit()) + text + "\n" # ich weiß unnötig kompliziert <!--- !!!
with open('MemHistory.txt', 'a') as f:
f.write("%s" % textmituhrzeit)
Code: Alles auswählen
def write_memory_log(text):
with open('MemHistory.txt', 'a') as f:
f.write('{0} {1}\n{2}\n'.format(time.asctime(), str(text), '#'*40))
Wenn du so viele Dateizugriffe hast und dort den Fehler vermutest, würde es dir vielleicht helfen auf eine Datenbank zurück zu greifen.