Timer Programm stürzt nach einigen Stunden ab



  • Hallo,

    seit ein paar Wochen hänge ich an meinem Problem, daß mein Programm mit Timer'n nach einigen Stunden zusammenbricht.
    Habe versucht einige Prozesse auszulagern daß diese nicht im Timer ständig durchgefühst werden müssen wie z.B. einige Informationen und Bilder aus Dateien laden.
    Auch eine andere Timer Funktion habe ich verwendet, da ich gelesen habe daß im Standard Timer das Betriebsystem mit Queues sehr belastet wird und diese auch eine Max. Laufzeit in Tagen besitzen.
    Verwende jetzt den ZylTimer der mit Treads arbeiten soll.

    Irgend was muss ich wohl falsch behandeln, bin jetzt an der Grenze und bitte um Rat.

    Hier einige Auszüge aus meinem Code...

    //Unit1.cpp
    #include <DateUtils.hpp>
    #include <conio.h>
    #include <fstream.h>
    #include <process.h>
    #include <dir.h>
    #include <shlwapi.h>
    #include <stdlib.h>
    #include <windows.h>
    #include <iostream.h>
    #include <urlhist.h>
    #include <vcl.h>
    #pragma hdrstop
    #include <stdio.h>
    #include "Unit1.h"
    #include "Unit2.h"
    #include "Unit3.h"
    #include "Unit4.h"
    #include "Unit5.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma link "SHDocVw_OCX"
    #pragma link "ZylTimer"
    #pragma resource "*.dfm"
    //#define _WIN32_WINNT 0x0403
    
    TStringList *banane = new TStringList();         //Platzhalter für Koordinaten
    Graphics::TBitmap *bmpbanane2 = new Graphics::TBitmap();   //Bildplatzhalter1
    Graphics::TBitmap *bmpbanane3 = new Graphics::TBitmap();   //Bildplatzhalter2 für Bildvergleich, davon habe ich einige deklariert
    .
    .
    TStringList *zitrone = new TStringList();         
    Graphics::TBitmap *bmpzitrone2 = new Graphics::TBitmap();   
    Graphics::TBitmap *bmpzitrone3 = new Graphics::TBitmap
    .
    .
    AnsiString workpath=ExtractFilePath(Application->ExeName);
    AnsiString Dir = workpath+"\\bilder"; //Verzeichnis der zu vergleichenden Bilder
    AnsiString Dir1 = workpath+"\\koordinaten"; //Verzeichnis der Koordinaten Informationen
    
    int firstrun = 0;
    
    //Unit1.h
    public:		// Benutzer-Deklarationen
    	__fastcall TForm1(TComponent* Owner);
            int bananeleft1, bananetop1; //für Umwandlung StrToInt der Koordinaten
            AnsiString leftbanane, toplbanane;  //Strings zur aufnahme der Koordinaten Informationen
            .
            .
             int zitroneleft1, zitronetop1; 
            AnsiString leftzitrone, toplzitrone; 
            .
            .
            TRect Quelle;
    
    //Timer
    void __fastcall TForm1::VerlaufTimer(TObject *Sender)
    {
    
    if (firstrun==0)  //nur wenn Timer das erste mal durchläuft
    {
    ForceDirectories(Dir1);
    //////////////////////////banane
    listbanane->LoadFromFile(Dir1+"\\banane.txt");  //Koordinaten für Canvas laden aus Datei
    leftbanane=listbanane->Strings[0];
    topbanane=listbanane->Strings[1];
    TryStrToInt(leftbanane, bananeleft1);
    TryStrToInt(topbanane, bananetop1);
    /////////////////////////zitrone
    listzitrone->LoadFromFile(Dir1+"\\zitrone.txt");
    leftzitrone=listzitrone->Strings[0];
    topzitrone=listzitrone->Strings[1];
    TryStrToInt(leftzitrone, zitroneleft1);
    TryStrToInt(topzitrone, zitronetop1);
    .
    .
    .
    ForceDirectories(Dir);
    ////////////////////////banane
    bmpbanane2->LoadFromFile(Dir+"\\banane.jpg");     //Bilder für Vergleich laden aus Datei
    bmpbanane3->LoadFromFile(Dir+"\\banane1.jpg");
    ////////////////////////banane
    bmpzitrone2->LoadFromFile(Dir+"\\zitrone.jpg") ;
    bmpzitrone3->LoadFromFile(Dir+"\\zitrone1.jpg") ;
    .
    .
    .
    }
    if {verlauf == "banane")     
    {
    resultstatus1 = 0,resultstatus2 = 0,resultstatus3 = 0;   
    Graphics::TBitmap *bmp1 = new Graphics::TBitmap();    //Bitmap für Canvas Bildvergleich anlegen
    bmp1->SetSize(size1,size1); 
    TCanvas* Canvas = new TCanvas();  //Canvas anlegen
    Canvas->Handle = GetDC(Form1->Handle);  //Canvas Handle auf Form zuweisen
    Quelle = Rect(bananeleft1 +1,  bananetop1 +1 , bananeleft1 + 16,bananetop1 +16 );  //Form Ausschnitt festlegen aus geladenen Koordinaten
    bmp1->Canvas->CopyRect(bmp1->Canvas->ClipRect, Canvas, Quelle);  //bmp1 FormAusschnitt zuweisen
    
    for (int x = 0; x < size1; x++) {                  //RGB werte ermitteln mit ScanLine
       PRGBTriple  z = (PRGBTriple)bmp1->ScanLine[x];
       int rs =  z[x].rgbtRed;
       int gs =  z[x].rgbtGreen;
       int bs =  z[x].rgbtBlue;
    	resultstatus1 += (rs+gs+bs);
    	}
    sresults1 = IntToStr(resultstatus1);
    
    for (int x = 0; x < size1; x++) {                  //RGB werte ermitteln mit ScanLine
       PRGBTriple	z  = (PRGBTriple)bmpbanane2->ScanLine[x];
       int rs =  z[x].rgbtRed;
       int gs =  z[x].rgbtGreen;
       int bs =  z[x].rgbtBlue;
    	resultstatus2 += (rs+gs+bs);
    	}
    sresults2 = IntToStr(resultstatus2);
    
    for (int x = 0; x < size1; x++) {                    //RGB werte ermitteln mit ScanLine
       PRGBTriple	z = (PRGBTriple)bmpbanane3->ScanLine[x];
       int rs =  z[x].rgbtRed;
       int gs =  z[x].rgbtGreen;
       int bs =  z[x].rgbtBlue;
    	resultstatus3 += (rs+gs+bs);
    	}
    sresults3 = IntToStr(resultstatus3);
    Edit1->Text = sresults1 +" "+ sresults2 +" "+sresults3;
    
    if (sresults1 == sresults2 || sresults1 == sresults3)   //RGB Werte vergleichen ob bmp1 gleich bild1 oder bild2 ist
    {
    //mach was   
    delete bmp1, Canvas ;    //bmp1 und Canvas löschen speicher freigeben 
    }
    else
    {
    delete bmp1, Canvas;
    }
    }
    .
    .
    .
    if (verlauf == "zitrone")
    {
    resultstatus1 = 0,resultstatus2 = 0,resultstatus3 = 0;
    Graphics::TBitmap *bmp1 = new Graphics::TBitmap();
    bmp1->SetSize(size1,size1);
    TCanvas* Canvas = new TCanvas();
    Canvas->Handle = GetDC(Form1->Handle);
    Quelle = Rect(zitroneleft1 +1,  zitronetop1 +1 , zitroneleft1 + 16,zitronetop1 +16 );
    bmp1->Canvas->CopyRect(bmp1->Canvas->ClipRect, Canvas, Quelle);
    
    for (int x = 0; x < size1; x++) {
       PRGBTriple  z = (PRGBTriple)bmp1->ScanLine[x];
       int rs =  z[x].rgbtRed;
       int gs =  z[x].rgbtGreen;
       int bs =  z[x].rgbtBlue;
    	resultstatus1 += (rs+gs+bs);
    	}
    sresults1 = IntToStr(resultstatus1);
    
    for (int x = 0; x < size1; x++) {
       PRGBTriple	z  = (PRGBTriple)bmpzitrone2->ScanLine[x];
       int rs =  z[x].rgbtRed;
       int gs =  z[x].rgbtGreen;
       int bs =  z[x].rgbtBlue;
    	resultstatus2 += (rs+gs+bs);
    	}
    sresults2 = IntToStr(resultstatus2);
    
    for (int x = 0; x < size1; x++) {
       PRGBTriple	z = (PRGBTriple)bmpzitrone3->ScanLine[x];
       int rs =  z[x].rgbtRed;
       int gs =  z[x].rgbtGreen;
       int bs =  z[x].rgbtBlue;
    	resultstatus3 += (rs+gs+bs);
    	}
    sresults3 = IntToStr(resultstatus3);
    Edit1->Text = sresults1 +" "+ sresults2 +" "+sresults3;
    
    if (sresults1 == sresults2 || sresults1 == sresults3)
    {
    //mach was
    delete bmp1, Canvas ;
    }
    else
    {
    delete bmp1, Canvas;
    }
    }
    .
    .
    .
     firstrun=1;  //Timer ist einmal durchlaufen bilder und Koordinaten werden nicht mehr geladen beim nächsten Durchlauf
    
    }
    

    Ab und zu hängt sich der Timer bei einem bestimmten Vergleich auf, doch das habe ich mit einem weiterem Timer der den ersten durch ein Zeitstempel prüft umgangen, der den VerlaufTimer wieder startet.(gefällt mir nicht)

    Das grössere Problem ist jedoch das komplette abstürzen des VerlaufTimers nach ca. 20000 Durchläufen.

    Was kann ich den ausser bmp1 und Canvas an Speicher wieder freigeben beim durchlaufen?

    Ist meine Behandlung der Vergleiche so machbar?

    Sollte ich für den Vergleich eine exerne Funktion bauen und in diese die Koordinaten und Bilder übergeben?

    Fakt ist ich bin mitlerweile Ratlos, für jede Hilfe bin ich sehr dankbar.

    Wünsche noch was...



  • Auf den ersten Blick sind mindestens die Zeilen 75, 79, 126 und 130 fatal, sie machen nicht das, was du glaubst. Lies mal nach, was der Komma Operator macht und überleg dir, warum dein Code nicht ok ist.
    Das Problem sind nicht die Timer, sondern dass du Speicherlecks en masse erzeugst und dem Prozess hinterher der Speicher ausgeht.

    Statt roher Zeiger solltest du gucken, ob du nicht Smart Pointer benutzen kannst.

    PS:
    Dein Verfahren, um zu prüfen, ob zwei Bilder gleich sind, passt auch nicht. Du läufst mit einem Index durch alle ScanLines (vertikal) einer Bitmap und greifst mit dem gleichen Index auf die Pixel der ScanLine zu (horizontal). Du addierst also die RGB-Anteile der Bilddiagonalen auf, statt alle Pixel der Bitmap zu behandeln. Und letztendlich addierst du die Farbanteile auf und vergleichst sie dann, aber durch die Addition sind RGB(1,0,0), RGB( 0,1,0 ) und RGB(0,0,1) gleichwertig. Dein Verfahren würde also z.B. komplett rote, komplett grüne und komplett blaue Bilder als identisch ansehen.

    Und noch was:
    Bist du dir sicher, dass deine Bitmap wirklich 24bit Farbtiefe für den RGBTRIPLE Zugriff besitzen? Ich weiß nicht, was die Default-Farbtiefe für TBitmap Objekte ist, aber ich würde sie explizit setzen.



  • DocShoe schrieb:

    Auf den ersten Blick sind mindestens die Zeilen 75, 79, 126 und 130 fatal, sie machen nicht das, was du glaubst. Lies mal nach, was der Komma Operator macht und überleg dir, warum dein Code nicht ok ist.

    Also Komma ist nicht immer als Aufzählungs Operator zu sehen...
    So wie ich es verstehe wird wohl bmp1 nicht gelöscht wenn Canvas einen gewissen Wert besitzt... hab das jetzt so umgeschrieben..

    delete bmp1;
    delete Canvas;
    

    DocShoe schrieb:

    Das Problem sind nicht die Timer, sondern dass du Speicherlecks en masse erzeugst und dem Prozess hinterher der Speicher ausgeht.

    Ja das ist auch mein Gedanke, mit meinem kleinen Wissen dazu hab ich keinen Ansatz mehr gesehen. Danke Dir daß Du mich auf das kleine Komma da aufmerksam gemacht hast 😋
    Muss ich den noch weitere Platzhalter hier freigeben ausser bmp1 und Canvas?

    DocShoe schrieb:

    Statt roher Zeiger solltest du gucken, ob du nicht Smart Pointer benutzen kannst.

    Smart Pointer hab ich mir angesehen, der Vorteil ist wohl daß der Pointer die Speicher freigaben selbst übernimmt und ich mir über deletes keine gedanken mehr machen muss.
    Werd mal schauen wie weit ich das begreifen und umsetzen kann, doch wenn ich kein delete vergesse um speicher freizugeben, sollte ich auch an mein ziel kommen?

    DocShoe schrieb:

    PS:
    Dein Verfahren, um zu prüfen, ob zwei Bilder gleich sind, passt auch nicht. Du läufst mit einem Index durch alle ScanLines (vertikal) einer Bitmap und greifst mit dem gleichen Index auf die Pixel der ScanLine zu (horizontal). Du addierst also die RGB-Anteile der Bilddiagonalen auf, statt alle Pixel der Bitmap zu behandeln. Und letztendlich addierst du die Farbanteile auf und vergleichst sie dann, aber durch die Addition sind RGB(1,0,0), RGB( 0,1,0 ) und RGB(0,0,1) gleichwertig. Dein Verfahren würde also z.B. komplett rote, komplett grüne und komplett blaue Bilder als identisch ansehen.

    OK, hab da nähmlich mit ähnlich aussehenden Bilder schon probleme... hmm sollte ich lieber die RGB Werte nicht Addieren sondern einzelnt vergleichen...?

    DocShoe schrieb:

    Und noch was:
    Bist du dir sicher, dass deine Bitmap wirklich 24bit Farbtiefe für den RGBTRIPLE Zugriff besitzen? Ich weiß nicht, was die Default-Farbtiefe für TBitmap Objekte ist, aber ich würde sie explizit setzen.

    In den Code Bespielen war die Prüfung auch dabei, da ich die Bilder selbst auch mit dem Programm erzeuge, bin ich davon ausgegangen daß ich die Prüfung nicht brauche... aber auch diesen Rat werde ich beherzigen danke.



  • Zu jedem new gehört ein delete , solange du das beachtest ist alles in Ordnung. Smart Pointer nehmen dir da einiges an Arbeit ab. Sie sind zu empfehlen aber nicht nicht zwingend erforderlich.

    Zum Vergleichen von zwei Bitmaps mit 24 Bit Farbtiefe kannst du folgende Funktion benutzen (ungetestet):

    #include <Graphics.hpp>
    
    #include <cassert>
    #include <cstring>
    
    bool equals( TBitmap* lhs, TBitmap* rhs )
    {
       // Bitmaps müssen existieren und 24bit Farbtiefe besitzen
       assert( lhs && lhs->PixelFormat == pf24bit );
       assert( rhs && rhs->PixelFormat == pf24bit );
    
       // Bitmaps müssen die gleiche Größe haben
       if( lhs->Width  != rhs->Width )  return false;
       if( lhs->Height != rhs->Height ) return false;
    
       // Länge einer Zeile in Bytes bestimmen
       unsigned int LineSize = sizeof( RGBTRIPLE ) * lhs->Width;
    
       // Bitmaps zeilenweise durchlaufen
       for( int i = 0; i < lhs->Height; ++i )  
       {
          // Zeilendaten byteweise vergleichen, bei Ungleichheit false zurückgeben
          if( std::memcmp( lhs->ScanLine[i], rhs->ScanLine[i], LineSize ) != 0 ) return false;
       }
       // Bitmaps sind identisch
       return true;
    }
    


  • Abend,

    habe deine Funktion mal ausprobiert DocShoe, jetzt sind zwei Probleme entstanden.^^

    Meine Bilder sind nicht im Format 24bit sonder 32bit *hust*, wenn ich die Prüfung ob sie 24bit sind rauslasse, sind irgendwie alle Bilder gleich für die Funktion.

    Jetzt google ich nach einer Möglichkeit die Bilder in 24bit beim lesen umzuwandeln, oder was Aufwand machen würde diese noch mal neu in 24bit zu speichern.

    Warum funktioniert den die Methode die ich gewählt habe?
    Oder funktioniert sie nur oberflächlich und im hintergrung werden Ressourcen gefressen?

    Wäre den diese Lösung ok?

    bmp1->PixelFormat = pf24bit;
    bmpbanane->PixelFormat = pf24bit;
    

    Der Vergleich mit dieser Funktion greift leider nicht immer, sehr merkwürdiges Verhalten.
    Einmal erkennt er die Bilder, dann mal wieder nicht, bewege ich die Maus auf die Taskleiste erkennt er es dann doch hmmm...



  • Wenn du Bilder mit 32 Bit Farbtiefe erzeugst kannst du im o.g. Beispiel einfach pf24bit durch pf32bit und RGBTRIPLE durch RGBQUAD ersetzen.
    Wenn du glaubst, dass sich dein Programm nicht so verhält, wie es soll, dann bau dir einen Test. Erzeuge verschiedene Bilder, von denen du genau weißt, wie sie aussehen und führe mit ihnen die Vergleiche durch.



  • yeah jetzt läuft es 😃

    die Umwandlung von 32bit in 24bit ist so wie es ausieht ok
    daß die Bilder teilweise nicht erkannt wurden lag wohl daran, daß die aus der Datei geladenen Bilder nicht die passende size hatten.

    Habe die size nach dem Laden noch mal gesetzt und es läuft sauber durch.
    Gleich angefangen meine Speicher Funktion umzubauen, daß er die Bilder als 24bit Farbtiefe speichert.

    Die bool Funktion hab ich im unit1.h untergebracht und rufe sie für den Vergleich von 3 Bildern so auf...

    if(verlauf == "banane")
    {
    .
    .
    .
    if (vergleich(bmp1,bmpbanane2)==true || vergleich(bmp1,bmpbanane3)==true)
    {
    //mach was
    }
    //die else hab ich jetzt weggelassen
    delete bmp1;
    delete Canvas;
    }
    

    mein Code ist jetzt um vielfaches kleiner dank Dir DocShoe, noch mals vielen Dank!!!

    Jetzt Dauertest ➡

    Wünsche was...



  • Hallo noch mal,

    irgendwo frisst des Programm immer noch Rechenleistung oder Speicher, im Taskmanager steigt zwar der Speicher Wert nicht mehr so drastisch, doch dafür die CPU Last.

    Habe jetzt aus der Funktion von DocShoe zwei gebaut um die if or Anfragen zu verarbeiten, leider sieht es nicht nach einer besserung aus.

    Wodurch kann den die CPU Last durch mein Code erzeugt werden?
    Hab jetzt den ZylTimer auch rausgeschmissen und den Standard TTimer verwendet.
    Alle Bilder mit 24bit gespeichert, daß er sie im Programm nicht mehr umrechnen muss, bis auf die von Canvas.

    In der Regel bricht er dann bei dem Bildvergleich ab...
    Meldet zuerst falscher Parameter und dan Systemressourcen erschöpft.
    hab mal im CodeGard Log geschaut, was da so ins augesticht, daß ich memcmp und vsnprintf sehr oft benutze, ist da meine Baustelle?

    Was Passiert wenn ich in drei verschiedenen Timern, die gleichen Variabeln verarbeite, ist das ein Problem?

    Eine Sleep Funktion soll doch die CPU entlasten?
    Habe einige Sleeps mit hinzugefügt an einigen Stellen, mir machts den anschein als ob die CPU Last grösser wird...

    Bin für jeglichen Rat dankbar, wünsche was...



  • Für solche Sachen eignen sich Profiler am besten, ab dem RAD Studio XE5 wird Smartbear´s AQTime im Bundle mitgeliefert.
    Wenn du keinen Profiler hast kannst du schrittweise Code auskommentieren und gucken, ob sich das Problem bessert. Wenn nach einem Schritt alles gut ist wird der Fehler wohl im auskommentierten Schritt liegen.

    Im Process Explorer kann man eine Spalte GDI Handles einblenden, wenn die unaufhörlich wächst hast du irgendwo eine Resource Leak.

    Dass memcmp sehr häufig aufgerufen wird ist kein Wunder, schließlich werden ja timer-gesteuert ständig Bitmap Vergleiche per memcmp durchgeführt. Welches Intervall hast du denn für deine Timer eingestellt?

    Sleep verringert zwar die CPU Last, legt den aufrufenden Thread aber auch schlafen. Ein Sleep im Hauptthread führt normalerweise zu trägen Reaktionszeiten der Anwendung, weil sie, während der Thread schläft, nichts tut. Keine gute Idee.

    Du solltest auch mal erklären, was dein Programm eigentlich leisten soll.



  • So nun läufts auch auf lange zeit ohne Fehler, folgendes habe ich geändert...

    von...

    Graphics::TBitmap *bmp1 = new Graphics::TBitmap();
    

    in...

    TBitmap *bmp1 = new TBitmap();
    

    Kann es sein daß ich hire Objecte deklariert habe mit Graphics:: und mit

    DeleteObject(bmp1);
    

    löschen muss?
    und dies hinzugefügt...

    ReleaseDC(Form1->Handle,NULL);
    ReleaseDC(NULL,Canvas->Handle);
    

    Naja es läuft erst mal... Vielendank für Rat und Tat 😃
    Schönes WE


Log in to reply