Speicherleck im VDR oder einem Plugin

  • HelmutB Danke für den Patch. Ich habe jetzt alle Patches aus dem Thread drin und mit dem letzten scheint es so, dass der Speicherverbauch +/- 1MB stabil pendelt. Vermute fast, die Ursache wurde gefunden - schöne Arbeit!


    Gruß

    Andreas

  • Ich habe meinen VDR jetzt mehrere Tage mit dem Patch von HelmutB betrieben und bin inzwischen überzeugt davon, dass damit das Speicherleck behoben ist. Die angedachte Änderung von hier werde ich nicht machen, da dadurch bereits in VDR selber an einigen Stellen weitere Änderungen erforderlich wären, um Abstürze zu vermeiden, und eventuell auch Plugins plötzlich nicht mehr funktionieren könnten. Den Patch vdr-2.5.6.malloc_trim.patch habe ich ausprobiert, werde ihn aber (zumindest zum jetzigen Zeitpunkt) nicht übernehmen.

    Den aktuellen Stand habe ich ins GIT (git.tvdr.de) eingespielt. Plugins brauchen nicht neu übersetzt zu werden.


    Danke an alle, die mitgesucht haben, und speziell an HelmutB für den Fix!

  • Ich glaube auch nicht, dass malloc_trim() wirklich notwendig ist. Er zeigt nur, dass der Speicherverbrauch des VDR doch nicht bis ins Unendliche anwächst.

    Ich vermute, dass der Speichermanager sehr kleine Speicherblöcke nicht sofort in seine Tabellen und Listen für freien Speicher einträgt, sondern vorerst nur in einer Art Todo-Liste und sich erst dann darüm kümmert, wenn freier physischer Speicher tatsächlich knapper wird (oder er mit malloc_trim dazu aufgefordert wird).


    Ein mögliches Speicherleck hätte ich noch gefunden: in CreateFont wäre im Fall von !f->Hight() der cFont *f vor dem folgendem new cDummyFontfreizugeben.

    Code
    Font *cFont::CreateFont(const char *Name, int CharHeight, int CharWidth)
    {
      cString fn = GetFontFileName(Name);
      cFont *f = *fn ? new cFreetypeFont(fn, CharHeight, CharWidth) : NULL;
      if (!f || !f->Height()) <-------------------------------------------------HIER
         f = new cDummyFont(CharHeight, CharWidth);
      return f;
    }

    LG Helmut

  • Da hast du Recht, wobei das in der Praxis wohl eher unwahrscheinlich ist.

    Nichtsdestotrotz dürfte das hier helfen:

  • Den aktuellen Stand habe ich ins GIT (git.tvdr.de) eingespielt.

    Ich verwende den delete-d patch erfolgreich mit 2.4.7. Da 2.4.x der stable branch ist, der auch von vielen Distributionen verwendet wird, wäre eine Version 2.4.8 im git vieleicht hilfreich für Paket-Pfleger.

  • Da 2.4.x der stable branch ist, der auch von vielen Distributionen verwendet wird, wäre eine Version 2.4.8 im git vieleicht hilfreich für Paket-Pfleger.

    da wäre ich auch für!

    VDR1: ACT-620, Asus P8B75-M LX, Intel Core i3-3240, 4 GB DDR3 RAM 1600 MHz, passive Geforce GT1030 von MSI, Sandisk 2TB SSD, 2xWinTV DualHD, Atric-IR-Einschalter. SW: Xubuntu 20.04 auf 64GB Sandisk SSD.

    VDR2: Odroid N2+ mit CoreELEC und Ubuntu in chroot, WinTV DualHD

    VDR3: Tanix TX3 mit CoreELEC und Ubuntu in chroot, WinTV DualHD

  • Auch wenn dieses Leck gefunden ist -übrigens: super Arbeit! :tup- ist das Thema ja noch nicht ganz vom Tisch. Bei einigen Plugins bestand, wenn ich recht erinnere, ja auch der Verdacht.


    Man kann "new" und "delete" überschreiben und dann eigene Logfunktionen bauen, nichts anderes machen sicherlich die Leck-Detektoren.

    Libleak macht das so für malloc, free, calloc, realloc und fork, siehe libleak.c Zeile 680-750.

    Die "Magie" findet in den paar Zeilen statt, der ganze Rest ist nur die Auswertung.

    Was nach LEAK_EXPIRE Sekunden nicht freigegeben wurde, wird als may-leak geloggt.

    Bei sinnvoller Wahl dieser Zeit sollte man kurzfristig benutzte Puffer usw. schon mal aus dem Log haben.

    Blöderweise bleibt beim VDR noch immer viel zu viel drin.


    Das Konzept von Libleak ist eigentlich echt gut, man muss nur überlegen, wie man die ganzen Meldungen bzgl. EPG los wird.

    Möglichkeit 1: Man schaltet das EPG ab. (zB. mittels EPGboarder-Plugin) Das Macht aber nur Sinn, wenn man sicher ist, dass das Leck dann noch Aktiv ist.

    Möglichkeit 2: Man bastelt sich ein Skript, was logdatei von libleak ausmistet.


    Das EPG macht es auch generell so schwierig den Speicherverbrauch einzuschätzen.

    Die Events veralten über den Tag auch und werden weggeräumt. Morgens um 6 auf einen Schlag wieder einen Haufen neue.

    Das erzeugt schon ein imenses Rauschen und der langsame Abfall über den Tag ist tückisch. Ein kleines Leck sieht man so erst nach ein paar Tagen.


    Um das mal weiterzuspinnen: Kann man nicht auch gezielt ein "Wegräumen" erzwingen? Also nur mal angenommen ich lasse einen VDR nur ein paar Stunden laufen mit einem Logging wie oben beschrieben. Wenn das Aufräumen überall sauber läuft, dann sollte bei sauberem Beenden des VDR ja kein einziger Pointer nicht sauber freigegeben worden sein. Andernfalls kann ja was nicht stimmen. Natürlich räumt der Kernel dann den ganzen Prozess weg, aber sauber wäre eben wenn das Programm vor dem Eingreifen vom Kernel alles schon freigegeben hat.

    Gute Idee, das mal soherum zu versuchen.

    Eigentlich sollte doch direkt vor dem endgültigen "exit()" alles aufgeräumt sein, wenn sauber gearbeitet wurde.

    Globale Variablen und wahrscheinlich noch ein paar andere Sachen werden noch noch da, aber alles Speicherintensive, wie Listen und Puffer sollt freigegeben worden sein. Man müsste nur mal schauen, dass man eine gute Stelle erwischt, nicht dass implizt schon was weg geräumt ist, was man noch untersuchen will.

    Man könnte da mal einen Halt einbauen und schauen, wie es da mit dem Speicherverbrauch aussieht. Eigentlich sollte da nicht mehr viel sein, so dass es möglich wird Coredumps zu ziehen und die zu vergleichen.

    Wenn nach ein paar Tagen Laufzeit der Coredump grösstenteils aus "Leck" besteht, gibt das meist wertvolle Hinweise auf die Ursache.


    Ich habe kurz in die Datei reingesehen. VonListGarbageCollector oder Purge habe ich nichts gefunden, nur cSchedules::Cleanup().

    Da erwarte ich auch nicht was zu sehen, die Funktionen reservieren ja keinen Speicher.

    Viele der "frees after expired" dürften aber daher stammen. Da wird aber nicht der Callstack angegeben.



    Verständnisfrage:

    Von dem ListGarbageCollector gibt es doch nur eine Instanz, oder hab ich da was übersehen?

    Wenn dem so ist, könnte man Purge() theoretisch doch blockieren, in dem man jede Sekunde ein ListObject mit Put() rein schiebt?

    Gruss
    SHF


  • Von dem ListGarbageCollector gibt es doch nur eine Instanz,

    Ja, es gibt derzeit nur den einen, Dazu habe ich aber eine andere Idee:


    Es ist ja nicht notwendig, im ListGarbageCollector alte cEventszu löschen und dafür in eit.c. immer neue zu erstellen. Diese könnten ja stattdesen aus dem GarbageCollector geholt und wiederverwendet werden.

    Ich habe auch schon damit begonnen, einer cList bei Bedarf einen eigenen GarbageCollector mitgeben zu können, Das sollte die vielen "new" und "delete" Operationen beim EPG-Scan nach einer gewissen Zeit überhaupt nicht mehr notwendig machen.Und wo etwas wäre auch bei cHash nützlich, da die beiden Hashes eventsHashID und eventsHashStartTimeebenfalls permanent cHash-Elemente erstellen und löschen.


    Helmut

    HelmutB passed unfortunately away on July 21, 2022 ... RIP 🖤

  • Da 2.4.x der stable branch ist, der auch von vielen Distributionen verwendet wird, wäre eine Version 2.4.8 im git vieleicht hilfreich für Paket-Pfleger.

    Ich denke eher daran, eine neue Stable Version 2.6 freizugeben. Das mit den Pattern-Timern funktioniert inzwischen ja ziemlich gut, und dann wären alle wieder auf dem gleichen Stand. Wäre das was?

  • kls Ich erwarte gar nicht, dass du es übernimmst, es interessiert mich nur selbst, ob es bei langlebigen Listen oder Hashes die sich stärk ändern ev. Vorteile bringt.

    Ich stelle mir die Sache auch eher einfach vor:


    cListGarbageCollector bekommt zum Put() noch ein Get() und jeder GarbageCollector wird einer neuen cList::GarbageCollectors hinzugefügt. Ein cGarbageCollectors::Purge() arbeitet diese Liste dann ab.

    Bei cHashwäre es auch sehr einfach. cHashBase ergänze ich um einen Pointer für einen GarbageCollector und in cHashBase::Add()und cHashBase:Del()wird mit oder ohne GarbageCollector gearbeitet. Da würde sich nach außen nichts ändern.

    Ähnlich bei cListBase, hier würde ich useGarbageCollectorzu einem Pointer auf einen GarbageCollector machen, cListBase::Del()berücksichtigt jetzt schon einen GarbageCollector, neue Objecte werden entweder direkt über cGarbageColletor::Get() geholt oder mit newerstellt.


    Ich werde einmal so versuchen und wenn etwas sinnvolles herauskommt kann ich es ja posten.

    LG Helmut

    HelmutB passed unfortunately away on July 21, 2022 ... RIP 🖤

  • Ich denke eher daran, eine neue Stable Version 2.6 freizugeben. Das mit den Pattern-Timern funktioniert inzwischen ja ziemlich gut, und dann wären alle wieder auf dem gleichen Stand. Wäre das was?

    :) Klasse!

  • Eine Frage habe ich bzgl "Errors in Recordings"


    Kann das vielleicht irgendwie ausgeschaltet werden?

    Ich hab manche aufnahmen mit Fehler aber die lassen sich einwandfrei abspielen


    Auch gibt’s meiner Meinung nach keine einfache Möglichkeit die Datei zu reparieren.


    Danke

  • und passt nicht gerade zum Thema ;)


    vdr-User-# 755 to_h264 chk_r vdr-transcode github

  • Bei einigen Plugins bestand, wenn ich recht erinnere, ja auch der Verdacht.

    Hmm, wäre es nicht gut, das in einen extra Thread auszulagern?

    Hier kann kls helfen (hat!), aber bei Plugins wird der jeweilige Autor/Maintainer des Plugins gefragt sein, sein Plugin zu checken..


    Klingt für mich nach anderer Baustelle, auch wenn das Thema *ähnlich* ist.

  • carel Wie lautet das Thema hier? Oder hast Du verlernt wie man Ontopic Posts verfasst bzw. neue Threads zu neuen Fragen öffnet?

    HowTo: APT pinning

  • Hmm, wäre es nicht gut, das in einen extra Thread auszulagern?

    Hier kann kls helfen (hat!), aber bei Plugins wird der jeweilige Autor/Maintainer des Plugins gefragt sein, sein Plugin zu checken..


    Klingt für mich nach anderer Baustelle, auch wenn das Thema *ähnlich* ist.

    Das Thema schliesst Plugins ein. Wenn ein Plugin explizit untersucht wird, macht neuer Thread Sinn.


    vdr-User-# 755 to_h264 chk_r vdr-transcode github

  • Hmm, wäre es nicht gut, das in einen extra Thread auszulagern?

    Hier kann kls helfen (hat!), aber bei Plugins wird der jeweilige Autor/Maintainer des Plugins gefragt sein, sein Plugin zu checken..

    Grundsätzlich richtig, nur muss man dann erstmal rausfinden welches welches Plugin der Übeltäter ist.

    Da die ganzen Lecks in einem "Topf" landen, hat man erstmal exakt die Probleme wie hier, wenn man versucht das einzugrenzen.

    Ich erinnere mich auch noch wage, dass auch das hier behobene Leck anfangs einem der Ausgabe-Plugins vermutet wurde.


    Den Code zu durchsuchen und zu hoffen, dass man was finden, ist halt nicht besonders effizient. Besonders, wenn man nicht weiss, was und wo man suchen muss.

    Alle Versuche den Fehler erstmal einzukreisen, bevor man etwas ändert oder im Detail sucht, sind am EPG gescheitert.

    IMHO wäre also keine doofe Idee mal zu überlegen, ob man sich zukünftig die Arbeit erleichtern kann.


    Die Idee von M-Reimer mit dem "erzwungenen Aufräumen" erscheint mir Potential zu haben.

    Den VDR in einen ähnlichen Zustand, wie vor dem exit() ist kein grosses Ding, dann hätte man wenigstens einen Ausgangspunkt für Vergleiche.


    Das Chaos, dass das aktuelle Leck im Speicher angerichtet hat, sollte in so einem "aufgeräumten" Zustand auch noch vorhanden gewesen sein.

    Das heisst, man hätte zumindest gesehen, dass da was ist und auch wie viel. Und ich denke, man man hätte auch eine Idee, was es sein könnte und was nicht ist.


    Wenn ich die Zeit finde, werde ich über die Feiertage mal ein bisschen in die Richtung basteln.

    Es ist ja nicht notwendig, im ListGarbageCollector alte cEventszu löschen und dafür in eit.c. immer neue zu erstellen. Diese könnten ja stattdesen aus dem GarbageCollector geholt und wiederverwendet werden.

    Ich weiss nicht, ob sich das lohnt.

    Da sich die Länge der Strings ziemlich sicher ändern wird, gewinnt man nicht viel, befürchte ich.


    Meine Frage war eher deshalb, weil der ListGarbageCollector theoretisch blockieren könnte, wenn sich da viel tut.

    5 Sekunden sind eine schon eine recht lange Zeit, so dass der Timeout mehrfach zurückgesetzt werden könnte. In der Zeit könnte sich einiges im ListGarbageCollector anstauen.

    Dauerhaft wird es wohl nicht bockieren, aber für die Dauer eines EPG-Scan halte ich es für denkbar. Im Worst Case hätte man dann das EPG 2 mal im RAM liegen.

    Bei vielen Kanälen und wenig RAM kann das schon eng werden.


    Ich denke eher daran, eine neue Stable Version 2.6 freizugeben.

    :tup

    Trotzdem möchte ich den Wunsch mach einer finalen, heilen Version 2.4.8 äussern.

    Nicht alle User können (oder wollen) gleich komplett Updaten (mit den Plugins zieht das ja immer so einen Rattenschwanz hinterher). Der eine oder andere wird also noch eine Weile beim 2.4 Zweig bleiben und da wäre es schön, wenn die letzte offizielle Version "abgedichtet" ist.

    Gerade bei diese doch recht "kritischem" Fehler sehe ich sonst gepatchte 2.4.7 Pakete kommen, was für User und Paketbauer nicht wirklich hilfreich ist.

    Gruss
    SHF


  • Ich möchte mich erstmal bei allen bedanken, die geholfen haben, das Leck zu finden. Besonderen Dank geht an HelmutB, der das Leck gefunden hat. Saubere Arbeit die du geleistet hast, Helmut!


    Für mich wird es aber wohl erstmal bei dem Leck bleiben, denn ich habe keine Ahnung wie ich den Patch auf mein System bringen soll. Vielleicht übersehe ich den einfachen Weg. Aber so wie ich das überblicke, bleibt mir nur das selbst übersetzen des VDR. Da ich sowas noch nie gemacht habe, und das System produktiv genutzt wird, traue ich mich da nicht ran. Der VDR nimmt unter anderem jeden Abend AWZ für meine Frau auf. Wenn das schief geht... :/


    EDIT: Kann ich mich grob an dieser Anleitung orientieren? Scheint überschaubar, ist aber von 2013.

    Der Punkt 1 müsste dann in meinem Fall

    Code
    deb-src https://packages.e-tobi.net/vdr-experimental stretch base vdr-multipatch addons

    heißen?

    In Punkt 4 müsste ich den sourcecode aller Plugins installieren, die ich nutze?

    Zwischen Punkt 5 und 6 müsste der Patch von HelmutB rein?

    Alle folgenden Schritte für jedes Plugin welches ich installiert habe?


    EDIT2: Klaus hat geschrieben, dass die Plugins nicht neu gebaut werden müssen. Das heißt dann, Punkt 1-6+11, den Rest kann ich ignorieren?

    3 Mal editiert, zuletzt von Marcus 2208 () aus folgendem Grund: Link zur Anleitung vergessen

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!