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.
(...)
Arbeitsspeicher sparend coden
- miracle173
- User
- Beiträge: 127
- Registriert: Samstag 6. Februar 2016, 00:28
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.