Cannot fork: Cannot allocate memory | BlockingInformParent

Begonnen von Burny4600, 14 Februar 2018, 10:33:06

Vorheriges Thema - Nächstes Thema

fhemxperte

Zitat von: rudolfkoenig am 18 Oktober 2019, 01:01:03
Ich habe ein Speicherloch in HttpUtils_gethostbyname bei gesetztem dnsServer mit debian/buster, perl 5.28 gefunden und gefixt.
Evtl. tritt das Problem auch mit anderen Perl-Versionen auf, das habe ich aber nicht verifiziert.
Es hat ca 10kb pro Lookup verloren, wenn die IP nicht im Cache war. Das bedeutet ca 1MB pro Tag und Adresse, wenn TTL auf 900s gesetzt ist, wie bei www.klack.de
Ich tippe auf einem perl Bug, es ist mir aber zu kompliziert, um es nachzuweisen.


Hi rudolfkoenig,

ziemlich cool, dass du das Leck gefunden hast. Scheinbar, war es das, was den Speicheranstieg bei mir verursacht hat (und wahrscheinlich bei ganz vielen anderen). Es wird bestimmt nicht das einzige Leck sein, aber dafür ein sehr zentrales. Das Leck ist mindestens in den Perl Versionen "perl 5, version 20, subversion 3 (v5.20.3)" bis zu deiner eingesetzten 5.28 vorhanden.

Zur Verdeutlichung habe ich nochmal ein neues Diagramm beigefügt.
1 = Der Test ohne das dnsServer Attribut - Ergebnis: Perfekte horizontale Gerade
2 = Der Test mit dnsServer Attribut inkl. Updates usw - Ergebnis: Speicherleck, ansteigende Gerade
3 = Der Test nach Update mit gefixtem HttpUtils_gethostbyname - Ergebnis: (bisher) perfekte horizontale Gerade

Meinerseits war es Zufall, dass ich von IP Adressen auf interner DNS-Auflösung umstellen wollte und der Speicher anstieg, aber manchmal braucht es genau so etwas.

Vielen Dank soweit.

Gruß,
Michael

parabacus

Hallo zusammen!

Ich bin auch schon einige Zeit betroffen und lese auch schon länger mit. Leider sind meine Kenntnisse zu gering, um bei der Problemsuche im Detail zu helfen, jedoch kann ich jetzt auch bestätigen, dass es bei mir auch an der Verwendung von HTTPMOD liegt.

Ich lese meinen PV-Wechselrichter damit aus - genau nach dieser Umsetzung, was eigentlich bisher auch problemlos funktioniert:
https://forum.fhem.de/index.php/topic,46685.msg730900.html#msg730900

Bei läuft das auf einem RasPi 3 mit Stretch und drauf ist Perl 5.24.1.

Als ich jetzt vor ein paar Tagen das Auslesen komplett entfernt habe, kann ich keinen Anstieg mehr feststellen.

Erst mal werde ich damit so leben - das Auslesen der Daten ist eh nur Spielerei und brauche ich nicht wirklich dringend.
Dennoch schon mal vielen Dank für die intensive Suche der Beteiligten, womit ich nun auch endlich weiss, was ich pragmatisch machen kann.
Stiebel Eltron LWZ 504 / FHEM auf Rasperry Pi 3 / THZ / Weather / TABLETUI / SB_SERVER / SB_PLAYER  / OBIS / Verkehrsinfo / speedtest / Presence / FRITZ / ZWDongle / ZWAVE / Calendar / CALVIEW/ IPCAM/ ABFALL / ESPEasy

rudolfkoenig

War in deinem Fall dnsServer aktiviert?
Wenn ja, hilft ein update auf die aktuelle Version?

parabacus

Soweit ich das bewerten kann, ist dnsServer nicht aktiviert - zumindest ist kein Attribut gesetzt.
Stiebel Eltron LWZ 504 / FHEM auf Rasperry Pi 3 / THZ / Weather / TABLETUI / SB_SERVER / SB_PLAYER  / OBIS / Verkehrsinfo / speedtest / Presence / FRITZ / ZWDongle / ZWAVE / Calendar / CALVIEW/ IPCAM/ ABFALL / ESPEasy

mumpitzstuff

#694
Ich glaube das Problem bei HTTPMOD gefunden zu haben und damit wahrscheinlich auch das Problem vieler weiterer Module.

HTTPMOD holt sich seine regular Expressions aus Attributen, die der Anwender anlegen kann. Diese werden dann auf den Inhalt der Webseite losgelassen. Und genau hier liegt der Hund begraben. Die eingelesenen regular Expression besitzen ein besonderes Encoding. Das sorgt jetzt dafür, dass die regular Expressions zwar funktionieren, diese aber Perl intern Memory Leaks erzeugen. Um meine Theorie zu untermauern habe ich folgendes probiert und siehe da, die Memory Leaks bei HTTPMOD waren weg.

use utf8;
use Encode qw(encode_utf8 decode_utf8);
$regex = decode_utf8($regex);


Das eigentlich fatale daran ist, das der Programmierer dieses Problem nicht einmal bemerkt, denn auf den ersten Blick funktioniert alles wunderbar. Erst auf den Zweiten schwindet der RAM dahin.

Könnte man dieses Problem irgendwie zentral angehen und somit das Problem für alle Module aus der Welt schaffen?

Ansonsten habe ich das in einem meiner Module wie folgt gelöst:

1.) use utf8; am Anfang des Moduls
2.) Alles was an Strings von außerhalb des Moduls kommt (jedes reading, attribut, user eingabe usw.) durch die Funktion decode_utf8() jagen
3.) Alles was an Strings raus geht aus dem Modul (reading schreiben usw. usw.) durch die Funktion encode_utf8() jagen

herrmannj

#695
Moin,

Es gibt (scheinbar) unter bestimmten Perl Version ein regex Mem leak: https://stackoverflow.com/questions/43288921/perl-program-leaking-memory-when-compiling-regex

https://github.com/perl/perl5/issues/15746

Würde mMn auch hier schon im thread behandelt. Scheinbar jedoch auch vom os, wetter, Sternenstand abhängig und scheinbar nie zu 100% reproduzierbar.

Möglich dass das bei dir funktioniert, woanders nicht. Hast du das per Trial and error gefunden oder kommen die Infos auch von wo anders?

rudolfkoenig

Ich gehe davon aus, dass die "utf8-Loesung" nur in bestimmten Faellen hilft, weil einmy $i=0;
while(1) { $i++; "bla" =~ /$i/ }
kein Speicher verliert.
Es waere aber interessant zu wissen, was genau zum Speicherverlust fuehrt.

Das Problem zentral anzugehen reicht nicht, es muessten alle Module angepasst werden, damit sie decode nach jedem read, und encode vor jedem write ausfuehren.
Das fuer alle FHEM-Module durchzufuehren und testen ist aussichtslos, und wuerde vermutlich zu mehr Speicherverbrauch fuehren, da alle Daten intern knapp doppelt so viel Platz einnehmen.

herrmannj

#697
Naja, Perl Version / Platform / distri und Sternenstand

Man braucht wohl compiled regex, was der Perl in der Optimierung manchmal selber macht. Ich konnte das nach einem Upgrade auf Buster Mal beobachten ohne das wirklich 100% auf die konkrete regex runter brechen zu können. Nach einem Perl downgrade war es weg. Dabei habe ich's dann auch belassen. Von daher schon möglich

Nachtrag: und ohne sicher sagen zu können das es wirklich regex waren

mumpitzstuff

#698
Zitat von: rudolfkoenig am 23 Oktober 2019, 22:13:01
Ich gehe davon aus, dass die "utf8-Loesung" nur in bestimmten Faellen hilft, weil einmy $i=0;
while(1) { $i++; "bla" =~ /$i/ }
kein Speicher verliert.

Das Problem tritt immer nur auf, wenn Daten von außen ins Modul kommen und Zeichen jenseits von Zahlen und Buchstaben enthält. Außen bedeutet in diesem Fall: Usereingaben. Wie und durch welche Mechanismen das genau passiert entzieht sich meiner Kenntnis. Meines Erachtens ist das Problem zweistufig. Irgendwoher kommt ein falsch encodierter String rein und dieser String verursacht in Stufe 2 Memory Leaks in Perl. Das Problem tritt auch nicht bei jedem Anwender auf, sondern hängt unter anderen mit der Locale Einstellung zusammen, vielleicht auch noch mit anderen Faktoren. Das blöde daran ist, das man das nicht gleich sieht. In meinem Kalendermodul hatten auch nur einige Personen Probleme z.B. mit Umlauten. Das lag dort ebenfalls am Encoding und wurde durch utf8 behoben. Das Fehlerbild passt exakt zu dem was wir hier die ganze Zeit beobachten, nämlich das einige das Problem massiv haben und andere es einfach nicht nachvollziehen können.
Ich kann aber gern mal die HTTPMOD Version zur Verfügung stellen, bin aber eigentlich nicht der Entwickler des Moduls. In diesem Thread gab es bereits mind. 2 Leute die ebenfalls Probleme damit hatten. Vielleicht können sie das Ergebnis im Fall von HTTPMOD verifizieren.

Meine locale Einstellungen sehen auf dem Debian Buster Pi so aus:
LANG=de_DE.UTF-8
LANGUAGE=
LC_CTYPE="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_PAPER="de_DE.UTF-8"
LC_NAME="de_DE.UTF-8"
LC_ADDRESS="de_DE.UTF-8"
LC_TELEPHONE="de_DE.UTF-8"
LC_MEASUREMENT="de_DE.UTF-8"
LC_IDENTIFICATION="de_DE.UTF-8"
LC_ALL=

mumpitzstuff

Im Anhang befindet sich die von mir veränderte HTTPMOD Version (entspricht ansonsten der aktuellsten Version). Bei mir ist damit der steigende Speicherverbrauch komplett weg, wie man auf dem anderen Bild sehen kann.

Getestet mit dem von Hardlife hier geposteten TV_Programme Device:
https://forum.fhem.de/index.php/topic,84372.msg981483.html#msg981483

Ich würde mich freuen, wenn Hardlife und parabacus das mal testen könnten.

StefanStrobel

Hallo,

so wie ich das sehe reden wir über einen Perl-Bug, der eine Ähnlichkeit zu einem alten Bug in Perl 5.24 hat und eigentlich behoben sein sollte.
Dieser scheint unter unklaren Bedingungen getriggert zu werden, hat aber damit zu tun, dass Regexes nicht richtig "verdaut" werden.
Da bei HTTPMOD die Regexes vom Anwender per Attribut definiert werden, kann es also vorkommen, dass der Anwender Sonderzeichen verwendet hat, die dem Perl-Interpreter in bestimmten Versionen und unter bestimmten Umständen nicht schmecken und zu einem Memory-Leak führen.
Habe ich das soweit richtig verstanden?

Leider tritt der Fehler bei mir ja nicht in dieser Form auf und ich kann es daher nicht nachstellen / testen.
Bisher nehme ich die Regexes aus $attr{$name}, ohne irgendwelche Umkodierungen.

Wenn es bei dem Problem um die interne Kodierung der Regexes aus Attributen geht, dann wäre es für mich naheliegender, in der AttrFn eine Art Bereinigung durchzuführen, bevor die Werte gespeichert werden. Da würde ich aber befürchten, dass andere Dinge (bei anderen Anwendern) nicht mehr funktionieren.

Wenn der Perl-Bug umgangen werden kann, wenn bei einem Regex-Match die Regex als utf8 interpretiert wird, dann würde ich nur vor dem betreffenden match ein use utf8 und direkt danach wieder ein no utf8 setzen. Nach meinem Verständnis passt das dann aber nicht zu dem vorgeschlagenen decode, denn der Interpreter würde dann ja erst recht utf8 Regexes erwarten ...

ich würde ungern ein Befehle in HTTPMOD einbauen, bei denen ich den Effekt nicht wirklich verstanden habe.
Was meint Ihr dazu?

Gruss
    Stefan

mumpitzstuff

So hier ein kurzes Script mit dem jeder prüfen kann ob er betroffen ist oder nicht.

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode qw(encode_utf8 decode_utf8);


sub leak($$)
{
  my ($data, $regex) = @_;
 
  my @matches = ($data =~ /$regex/);
 
  print "matches = ".join(", ", @matches)."\n" if (@matches);
}

sub noleak($$)
{
  my ($data, $regex) = @_;
 
  $regex = decode_utf8($regex);
 
  my @matches = ($data =~ /$regex/);
 
  print "matches = ".join(", ", @matches)."\n" if (@matches);
}


for (my $i = 0; $i < 9999; $i++)
{
  leak('title="SAT.1"><img<td class="timeRow"><div<div class="content"><a>match_first</a>', 'title="SAT.1"><img[\w\W]*?<td class="time[\w\W]*?Row">[\w\W]*?<div[\w\W]*?<div class="content">\s*<a[\w\W]*?>\s*(.*?)\s*<\/a>');
  leak('title="ORF 3"><img<div class="content"><a>match_second</a>', 'title="ORF 3"><img[\w\W]*?<div class="content">\s*<a[\w\W]*?>\s*(.*?)\s*<\/a>');
}


In dieser Version schaufelt mir das Script den RAM auf meinem Raspberry in Sekunden zu! Ersetze ich innerhalb der for Schleife "leak" durch "noleak" erhalte ich weiterhin matches und es wird kein RAM mehr verbraucht.

qed


herrmannj

Debian, perl 5.22 / Ubuntu 16.04.6 -> keine Auffälligkeiten

DS_Starter

Kann den Test wie von mumpitzstuff beschrieben 100%ig bestätigen.

perl5.28.1 / deb10u1 (2019-09-20)  Buster
ESXi@NUC+Debian+MariaDB, PV: SMA, Victron MPII+Pylontech+CerboGX
Maintainer: SSCam, SSChatBot, SSCal, SSFile, DbLog/DbRep, Log2Syslog, SolarForecast,Watches, Dashboard, PylonLowVoltage
Kaffeekasse: https://www.paypal.me/HMaaz
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/DS_Starter

rudolfkoenig

#704
osx, perl 5.18 => kein Speicherloch
ubuntu, perl 5.18 => kein Speicherloch

osx, perl 5.30 => Speicherloch
debian buster, perl 5.28 => Speicherloch


Nachtrag:osx, perl 5.24 => kein Speicherloch