FHEM Forum

FHEM - Entwicklung => FHEM Development => Thema gestartet von: zap am 01 April 2017, 09:33:49

Titel: Cannot fork: Cannot allocate memory bei GDS / BlockingCall
Beitrag von: zap am 01 April 2017, 09:33:49
Gestern hatte ich zum ersten Mal seit ich FHEM nutze folgenden Fehler im Log:

Cannot fork: Cannot allocate memory

Der Fehler tritt 1x pro Stunde auf, und zwar immer dann, wenn ich per AT für das GDS Device ein "get rereadcfg" ausführen lasse.
Ich glaube allerdings nicht, dass GDS dir Ursache ist sondern vielmehr der BlockingCall() Aufruf, den GDS ausführt. Der Fehler tritt nämlich auch auf, wenn z.B. OPENWEATHER per BlockingCall() ein Update macht.

Nach einem Neustart ist wieder alles in Ordnung. Auffällig ist, dass vor dem Neustart perl eine Memory Usage von >50% hatte. Nach dem Neustart liegt sie bei ca. 12%.

Kann es sein, dass Speicher nicht mehr korrekt freigegeben wird, wenn bei einem BlockingCall etwas schief geht?

Bin für Tipps dankbar, um den Fehler weiter eingrenzen zu können.
Titel: Antw:Cannot fork: Cannot allocate memory bei GDS / BlockingCall
Beitrag von: rudolfkoenig am 01 April 2017, 11:00:16
Ich vermute ein Speicherloch in einem der Module.

Sowas kann man auch mit perl produzieren, ich habe das bei einem XML-Parser erlebt, da musste ich den Speicher explizit freigeben.
Perl verwendet mWn einen Referenzzaehler fuer allozierte Bereiche, und gibt diese frei, wenn der Zaehler auf 0 faellt. Wenn man aber eine Mehrfachverkettung verwendet, dann funktioniert dieser Algorithmus nicht mehr.

Leider ist das nicht ganz trivial zu lokalisieren, mir faellt nur das Deaktivieren einzelner Module der Reihen nach ein.
Ich wuerde mit den Modulen anfangen, die irgendetwas mit XML machen :)
Titel: Antw:Cannot fork: Cannot allocate memory bei GDS / BlockingCall
Beitrag von: betateilchen am 06 April 2017, 19:27:48
Grundsätzlich kann man von Folgendem ausgehen: Der Speicherbedarf eines XML::Simple Objekts ist ca. 10 Mal so hoch wie die zugrundeliegende Datenmenge der XML Daten (z.B. Dateigröße der XML Datei)

Hinterher ist man immer schlauer. Würde ich heute GDS nochmal neu schreiben, würde ich XML::Twig verwenden anstatt XML::Simple.

Aber für eine solch grundlegende Änderung habe ich im Moment weder Zeit noch Lust. Noch dazu, wo der Deutsche Wetterdienst sich regelmäßig neue Datenstrukturen ausdenkt. Das war auch der Grund, das Modul schon vor längerer Zeit nach contrib zu verschieben.


Titel: Antw:Cannot fork: Cannot allocate memory bei GDS / BlockingCall
Beitrag von: zap am 07 April 2017, 11:08:12
Mittlerweile denke ich auch, dass insbesondere XML der Übeltäter ist, zumal ich in meiner Installation einige Module mit XML-Verwendung habe (GDS, mein eigenes HMCCU, ...).

Der Witz bei der Geschichte ist, dass selbst da, wo ich es selbst in der Hand habe und XML-Objekte explizit lösche (undef) bzw. sie eh aus dem Scope fallen, der Speicher nicht immer frei gegeben wird (vermutlich irgendwelche verbleibenden Referenzen in Perl, die das verhindern).

Aber was will man machen wenn ein Protokoll wie RPC nun mal XML verwendet?

Blöd ist halt, dass sich das Problem mit jedem Fork eines Prozesses oder dem Start eines Threads "verdoppelt", weil ja immer der fhem.pl Prozess in seiner vollen Schönheit bzw. kompletten Speicher geclont wird. Das schaukelt sich dann schnell hoch bis eben "Cannot fork" kommt.

Da wäre eine Architektur vorteilhaft, bei der jedes Modul ein eigener Prozess oder Thread ist, die dann über einen Message Bus (MQTT, RPC MQ o.ä) kommunizieren.

Titel: Antw:Cannot fork: Cannot allocate memory bei GDS / BlockingCall
Beitrag von: rudolfkoenig am 07 April 2017, 11:19:16
ZitatXML-Objekte explizit lösche (undef)
Ich meine mich zu erinnern, dass undef die falsche Wahl ist (das kan das perl runtime selbst), es muss ein explizites $doc->dispose sein (siehe http://search.cpan.org/~tjmather/XML-DOM-1.46/lib/XML/DOM/Parser.pod).

ZitatAber was will man machen wenn ein Protokoll wie RPC nun mal XML verwendet?
XML ist auch nur Text, man kann mit regexps einiges bewerkstelligen :). Oder man verwendet einen SAX Parser. Der ist zwar mAn nicht wesentlich besser als regexp, aber "Standard" und legt keine mehrfachverkettete Datenstrukuren an.