Schlimmer Fehler - Programm friert sporadisch nach gewisser Zeit ein - Timer in While-Schleife

  • Moin moin zusammen,

    habe eine kurze Frage. Ich habe eine sehr sehr komplexe Software erstellt und habe nachdem ich viele Funktionen in letzter Zeit eingebaut habe, das Problem, dass die GUI nach gewisser Zeit sporadisch einfriert. Ich kann diesen Fehler nicht nachstellen.

    Ich habe nun die vermutung das es am Timer / bzw. den Timern liegt die ich in der Scheife eingebaut habe.

    Frage in die Runde: Hat jemand ein Skript laufen, bei dem mehrere Timer in der Schleife laufen und welche Erfahrungen habt ihr damit gemacht? Ist es möglich das zwei Timer sich in die Quere kommen können und dann zum Freeze führen?

    Grüße,
    KriZza


    Anbei nur mal ein kleiner Ausschnitt der "While-Schleife"

  • Aus eigener Erfahrung kann ich dir sagen, dass die Fenster schnell einfrieren, wenn sie sehr oft angesteuert werden. Zum Beispiel, wenn du ein Label via ControlSetText in jedem Schleifen-Durchgang setzen lässt. Ich könnte mir vorstellen, dass du hier das selbe Problem hast:

    AutoIt
    If IniRead(@ScriptDir & "\CODE\TMPDATA\STATES\userdata.cw1", $readlogin1, "ActiveProfile", "") = "---" Then
    			WinSetTitle($main_form, "", $Titlename & " | Benutzer: " & $readshowname & " | Schulungsprofil: ---")
    		Else
    			WinSetTitle($main_form, "", $Titlename & " | Benutzer: " & $readshowname & " | " & _
    					"Schulungsprofil: " & $READPROFILE & " (" & IniRead(@ScriptDir & "\DATA\USERS\" & $readlogin1 & "\PROFILES\" & $READPROFILE, "GlobalInfo", "Date", "") & "-" & _
    					IniRead(@ScriptDir & "\DATA\USERS\" & $readlogin1 & "\PROFILES\" & $READPROFILE, "GlobalInfo", "DateEnd", "") & ")")
    		EndIf

    In diesem Teil deiner Schleife versuchst du den Titel des Fensters zu ändern - und das jede Sekunde. Und vollkommen unabhängig davon, ob sich der Titel eigentlich ändern würde oder nicht.

    Es gibt Tage, da trete ich nicht ins Fettnäpfchen. Ich falle in die Friteuse.

  • Ich habe nun die vermutung

    was dir NICHTS bringt, genauso wenig wie das rumgestochere im Nebel!
    Wieso benutzt du nicht die in Scite vorhandenen Debugging-Möglichkeiten wie bspw. DebugTrace oder Tracelines, um den "Fehler" erstmal zu lokalisieren?!

  • Ich hasse dieses rumgesochere im Nebel :P und das geht schon seit Wochen so.

    Ich bin echt dankbar für jeden Tipp.

    Ich nutze nur einen Bruchteil von Scite. DebugTrace oder Tracelines waren noch nicht dabei. Danke Andy, ich probiere es aus und berichte.

    Edit... Du meinst den Modus wo der mir jede Zeile in die Console schreibt? Bin mal gespannt. Das Grundscript hat 35.000 Zeilen Grundcode und habe noch 5-6 Untermodule die Parallel mitlaufen :D Mal einen Lasttest durchführen :D

  • genau so macht man das...
    Wenn dein Script jetzt einfriert, dann steht in der letzten Zeile der Console der zuletzt umgesetzte Befehl. Genausogut kann es sein, dass du in einer Schleife gefangen bist und nicht wieder herauskommst.
    Alles in allem musst du wissen, in welchem Codesegment der "Fehler" auftritt, um ihn näher einzugrenzen.
    Im nächsten Schritt lässt du dir nur im kritischen Segment die Meldungen ausgeben, ergänzt ggf. durch Variableninhalte.
    Schau dir dazu im Menü auch DebugtoConsole an, damit ( Cursor auf die Variable und dann ALT+d ) bekommst du Infos in der Console zum Variableninhalt.


  • Der bleibt auch beim Debug- Leider immer bei unterschiedlichen Stellen stehen. Ich knalle mir aus irgendwelchen Gründen den Speicher scheinbar voll. Diese Meldung kommt immer, seitdem ich den Debug aktiv habe. :/

  • Wenn du den Speicher vollknallst, hast du wohl irgendwo ein memleak produziert. Prüfe am besten Mal, ob du jeden Speicher, den du anforderst auch wieder freigibst.

    Übliche Kandidaten hierfür sind IniWrites, IniReads, FileWrites, FileReads, ... wenn dein Programm länger läuft, sollte all dies über Handles geschehen, da der Speicher sonst nicht freigegeben wird. Dies kann schnell zu einem memleak führen:

    Nehmen wir an, du hast eine Ini-Datei. Diese Ini-Datei ist - der Einfachheit halber 1MB groß. Jetzt stößt du einmal pro Sekunde 5 IniWrites an und gehst dabei über den FileNamen.

    Das bedeutet, dass AutoIt die Ini-Datei 5x pro Sekunde in den Speicher läd - kurz 5 MB/s. Ausgehend von - wieder der Einfachheit halber - 5 GB Arbeitsspeicher bedeutet dies, dass dein Speicher in 1000 Sekunden (also etwa 15 Minuten) aufgebraucht wäre, und es nicht möglich wäre, weiteren Speicher zu beziehen.

    Es gibt Tage, da trete ich nicht ins Fettnäpfchen. Ich falle in die Friteuse.

  • hmm, imho müsste dein Script schon ziemlich lange laufen, wenn die Scite-console den Speicher vollaufen lässt...

    Nimm die Trace-lines raus, und setze "von Hand" per ALT+d in jede der IF-Verzweigungen eine Abfrage.

  • Hat die Konsole nicht einen Überlaufschutz ?
    Dachte die Arbeitet ab einere gewissen Größe nach dem First in First out Prinzip. (Habe es aber jetzt nicht getestet, dafür müsste ich ja Stundenlang die Konsole vollschreiben lassen :D)

    - Zum Arbeitsspeicher: AutoIt kann maximal 4GB (früher mal 2) adressieren. Dein Error tritt auf, sobald diese erreicht sind.
    - Ini-Funktionen haben ein eingebautes FileOpen und FileClose, genauso wie die FileRead Funktionen. Wenn man überall ohne Handles arbeitet läuft da nichts über. (Jedenfalls meine Erfahrung dazu)
    - Wenn das Skript so viel Speicher braucht wird an irgendeiner Stelle RAM reserviert und nicht wieder freigegeben.
    - Falls du Maps und Arrays kombiniert nutzt wirst du das ändern müssen, da hier ein Memoryleak in AutoIt vorliegt.
    - Handles die nicht freigegeben werden verbrauchen etwas Speicher.
    - Extrem große Arrays (vllt zu Anfang klein und durch ArrayAdd über lange zeit sehr groß).

    Hier kannst du mal ausprobieren wie voll du das RAM bekommst bis der Fehler auftritt. Benutzt wird ein Großes Array mit String einträgen. Bei mir sind die 4GB in einigen Sekunden erreicht und das Skript stürtz ab. Benutzung auf eigene Gefahr, je nach Windowseinstellungen und vorhandenem RAM versucht er Daten auf die Festplatte auszulagern, was ohne SSD ekelhaft werden kann. Das soll nur ein Beispiel sein, wenn der String länger (und nicht immer gleich ist) verbraucht AutoIt wesentlich mehr RAM, so kann man die 4GB auch mit wesentlich kürzeren Arrays erreichen.

    lg
    M

  • Super vielen Dank für den Tipp / die Tipps. Dann werde ich mich mal auf die Suche machen ...
    Nur mal kurz eine Kennzahl, im Hauptscript sind 1246 IniRead´s hinterlegt.. Das wird auf jeden Fall dauern :/

    meint ihr ein "_FTP_ProgressUpload" / "_FTP_ProgressDownload" gehört auch dazu?

    Bei dem Skript zum Testen ist wirklich nach 4 GB schluss. Bei meinem Skript sieht´s so aus, als würde er über den Taskmanager den Speicher wieder freigeben :-/

  • Im Startpost steht ausschliesslich etwas übers "einfrieren" des Scripts, der Speicherüberlauf tritt doch nur bei Anwendung der Trace/Debuglines auf?!

    "Einfrieren" heißt, dass die GUI keine Eingaben mehr entgegen nimmt, oder dass keine erwarteten Programmaktivitäten beobachtbar sind.
    Ursachen dafür sind meist eine Endlosschleife oder eine vom Programm erwartete Userinteraktion.
    Wenn ich im Startpost sehe, dass sogar externe Programme involviert sind, vervielfacht sich das Problem!


    Nur mal kurz eine Kennzahl, im Hauptscript sind 1246 IniRead´s hinterlegt.. Das wird auf jeden Fall dauern

    Du sollst nicht jedes einzelne IniRead() dokumentieren, sondern das Problem im Code lokalisieren!
    Beim "Einfrieren" des Programms muss in der letzten Zeile der Console der Weg zum nächsten Schritt stehen...
    Und diesen nächsten Schritt musst du dann wieder eingrenzen! Und logischerweise ALLE ÜBERFLÜSSIGEN Debug-Lines rausschmeissen!
    Bis du zuletzt den Logikfehler oder Laufzeitfehler gefunden hast...


  • meint ihr ein "_FTP_ProgressUpload" / "_FTP_ProgressDownload" gehört auch dazu?

    kommt darauf an ob du die Handles von _FTP_Open und _FTP_Connect nur einmal erzeugst und wieder verwendest, oder ob du sie jedes Mal neu erstellst und die alten nicht mit _FTP_Close schliesst.

  • Mars: Meine Erfahrung hierzu: Wenn man nicht mit Handles arbeitet wird der Speicher nicht wieder frei gegeben. Das Problem hatte ich mal bei einem Dienst den ich zuerst via svrany laufen hatte und anschließend mit AlwaysUp. Letzteres schickte mir pro Tag 19 Mails dass das Programm über 150MB Arbeitsspeicher reserviert hatte. Und das, obwohl ich keine Maps verwendet habe nur einen Array zu dem keine Daten hinzugefügt werden und sonst fast ausschließlich Dateibefehle. Ansonsten nur noch einen Ping und das herunterladen einer XML-Datei die dann via FileFunktionen wieder eingelesen wurde. Kaum sind alle Dateioperationen (auch der Ini-Scheiss) auf Handles umgestellt worden habe ich das Problem nicht mehr beobachten können.

    Es gibt Tage, da trete ich nicht ins Fettnäpfchen. Ich falle in die Friteuse.

  • So, mit den ganzen Debug-Varianten bin ich leider nicht weiter gekommen.

    Nochmal kurz zum Fehler selber:
    Ich habe eine Hauptanwendung in der viele Grafiken stetig aktualisiert werden. Sporadisch ist das Programm eingefrohren / (friert evtl. noch ein). Es gibt keine großartigen Bewegungen mehr im Taskmanager, wobei die RAM und CPU Auslastung, auch bei dem Freeze sehr gering ist. Passiert dieses Phänomen verschwinden die Grafiken bei einem Mouseover. Interaktionen mit dem Programm sind auch nicht mehr möglich.

    2 Dinge habe ich geändert und der Fehler ist bislang nicht mehr aufgetaucht
    1: Update auf 3.3.14.1 von 3.3.12.0 --> seitdem werden auch die Controls bei mir richtig positioniert das war vorher nicht der Fall
    2: Ich lasse mir für 10 Rechner Desktopvorschaugrafiken anzeigen. In diese Funktion war ein globales "_GDIPlus_Startup()" und "_GDIPlus_Shutdown()" drin. Das lasse ich nun für jeden Rechner einzeln laufen, also 10 mal "_GDIPlus_Startup()" und "_GDIPlus_Shutdown()".

    Meint ihr das GDI Funktionen so ein verhalten verursachen können? Der Debug hat mir auch hier kein Aufschluss gegeben.

  • Der Debug hat mir auch hier kein Aufschluss gegeben.

    Verstehe ich ehrlich gesagt nicht.
    Um das mal krass zu formulieren willst du dass wir uns daran beteiligen im Nebel rumzustochern...

    Was ist der SINN von Debugging?
    Einen Fehler zu lokalisieren und diesen dann zu eliminieren. Der Sinn ist NICHT, irgendwelche Programmausgaben zu generieren, diese nicht zu beachten und darauf zu hoffen, dass sich der "Fehler" irgendwann selbst behebt oder irgendjemand anderes nach heftigem Reiben an der Kristallkugel eine Lösung in den Raum wirft!

    Wenn dein Programm "einfriert", welche Funktion (Programmabschnitt, Zeile) wurde zuletzt ausgeführt? Wie ist der Inhalt der in dieser Funktion benutzten Variablen?


    Meint ihr das GDI Funktionen so ein verhalten verursachen können?

    Es wäre nicht das erste mal, dass in einer esoterischen Funktion Bugs enthalten sein können, bei den "Standard"-GDI-Funktionen schließe ich das aber aus. IdR. werden dort nur die API-Aufrufe gewrappert.

    2 Dinge habe ich geändert und der Fehler ist bislang nicht mehr aufgetaucht

    So gehts auch, was war der Anlaß dafür?

  • Hallo zusammen,

    wollte euch nur kurz auf den neusten Stand bringen. Der Übeltäter ist gefunden. Das Standard-Debugging hat mir leider nichts gebracht. Evtl weil das Skript zu groß ist?! (Durch das Debugging ist das Programm auch eingefroren -.-) Da der Fehler leider in nicht nachvollziehbaren Abständen und nicht durch Aktionen nachgestellt werden konnte, musste alles auf den Prüfstand gestellt werden. Es tut mir an der Stelle leid, dass ich euch auch hab "im Nebel rumstochenern" lassen.

    Kurz zum Ergebnis: Ich habe in einem Timer alle 30 Sekunden ein _FTP_ProgressDownload gemacht. Das findet der Arbeitsspeicher wohl nicht so toll, obwohl in der FTPEx ordnungsgemäß FileOpen und FileClose aufgerufen werden.

    Diese Funktion mit anderen Parametern habe ich 10 mal am Stück aufgerufen und das alle 30 Sekunden. Dadurch ist das Programm im Laufe der Zeit weggefreezed.

    AutoIt
    _FTP_ProgressDownload($hConn7, @ScriptDir & "\CODE\TMPDATA\ERRORSTATES\CLIENTCACHE\ERROR." & $IPRECHNER01, "/TCFTP/" & $IPRECHNER01 & "/ERROR.data")
    If Not @error Then _FTP_FileDelete($hConn7, "/TCFTP/" & $IPRECHNER01 & "/ERROR.data")


    Viele Grüße
    KriZza