wxWidgets - Speicherleck



  • Hallo liebe Community,
    eig wollte ich mich mit meinem Problem direkt an wxWidgets (Forum) wenden, aber aus irgendeinem Grund akzeptieren die nicht meine Registrierung ^^ , weshalb ich mein Problem hier posten muss.

    Ich arbeite seit einiger Zeit mit wxWidgets und bin grundsätzlich sehr zufrieden. Nun habe ich folgendes Problem mein Kompiler (Visual Studio 2012) meldet Speicherlecks, was mich wundert, normalerweise achte ich immer sehr penibel auf Speicherfreigaben.

    Weshalb ich folgenden Code getestet hab:

    #include "wx/wx.h"
    
    #define _CRTDBG_MAP_ALLOC
    #include <stdlib.h>
    #include <crtdbg.h>
    
    class MyApp: public wxApp
        {
            virtual bool OnInit();
        };
    
    IMPLEMENT_APP(MyApp)
    
    bool MyApp::OnInit()
    {
    	_CrtDumpMemoryLeaks();
    	wxFrame* frame = new wxFrame(0,-1,"test",wxDefaultPosition, wxDefaultSize);
    	frame->Show();
    	SetTopWindow( frame ) ;
    
    	return true; 
    }
    

    Nichts großes, erzeugt nur nen Fenster, jedoch erhalte ich bei diesem Beispiel bereits Speicherleckmeldungen, was bedeutet, dass ich evtl iein Aufruf von wxWidgets nicht mache( der aber nötig wäre) oder aber Visual Studio kommt mit wxWidgets nicht klar^^

    Hoffe ihr könnt mir Helfen, ich nutze Visual Studio 2012 und wxwidgets 3.0.0

    mfG Hlymur



  • Naja, du machst ein new aber kein delete, daher wird wahrscheinlich die Warnung kommen.



  • Danke für die Antwort, als ich mit wxWidgets angefangen hatte, dachte ich auch immer, dass ich ja irgendwo ein delete brauche.

    http://wiki.wxwidgets.org/Avoiding_Memory_Leaks

    Auf der Seite steht, dass Frames und Dialogs ihre Member selbst löschen, die Frames solle man dann mit ->Destroy() freigeben. Die einzige Möglichkeit, die mir einfällt, ist das Fenster beim Schließen freizugeben (wxCloseEvent), wenn ich das hinzufüge:

    void CloseTest(wxCloseEvent& event)
    	{
    		Hide();
    		Destroy();
    		return;
    	}
    

    sollten laut wxWidgets-Aussage bei meinem (minimal)Test keine lecks auftreten, was jedoch trotzdem der Fall ist, selbst die Beispiele von wxWidgets haben laut Visual Studio Speicherlecks^^



  • Die Definition von Speicherleck ist manchmal 1.) unterschiedlich (bspw. auch bei fltk) und 2.) wann gemessen wird. D.h. angelegte Fenster koennten in der Library global verwaltet werden und erst nach beenden der main-Funktion geloescht werden. Fenster etc sind also "managed". Zu 1.) anstatt am Ende keinen erreichbaren Speicher mehr zu haben, bedeutet es, dass unbenutzbarer, allokierter Speicher sich waehrend der Laufzeit akkumuliert. Ob und was fuer wxWidgets zutrifft, weiss ich aber nicht.

    die Frames solle man dann mit ->Destroy() freigeben

    In deinem Link wird aber Close() empfohlen.



  • Close schickt ein Close-Event an das Fenster, womit angegeben wird, dass der Nutzer es schließen möchte. Das Standard Close-Event ruft einfach nur Destroy auf, womit ein Destroy-Event für das Fenster in die Event-Queue eingereiht wird und bei Einsatz dieses zerstört/befreit.
    Top-Level Fenster (Fenster ohne Parent) werden von der App verwaltet und bei Beendigung dieser aufgeräumt, das gleiche gilt für Childs von Parents. Diese hierarchische Struktur macht es unnötig, Fenster manuell zu befreien.
    Die Eventverarbeitungsschleife, welche nach Init startet und die Top-Level Fenster bedient (und diese abwärts ihre Childs), endet zeitgleich mit der App , wenn kein Top-Level Fenster mehr vorhanden ist und alle restlichen Events abgearbeitet sind - somit findet die Anwendung ein Ende.
    Wenn du bei deinem einen Top-Level Fenster den X Button drückst, wird ein Close erwirkt, was zu einem Destroy führt, was das Fenster befreit, die App ohne Top-Level Fenster zurücklässt und somit die Anwendung beendet.

    Fazit: MSVC kommt nicht mit wxWidgets klar. Was sind denn die Speicherleck-Meldungen?



  • Ich glaube auch, dass MSVC damit nicht klar kommt (evtl. nen anderes Programm zur Speicherleckfindung benutzen? )

    Naja der Dump ist sehr sehr lang ^^

    Hier mal ein Ausschnitt:

    Detected memory leaks!
    Dumping objects ->
    {4640} normal block at 0x006C3ED0, 24 bytes long.
     Data: <(H       fl     > 28 48 0A 01 CD CD CD CD A8 66 6C 00 00 00 00 00 
    {4639} normal block at 0x006C3F90, 24 bytes long.
     Data: <(H       el  >l > 28 48 0A 01 CD CD CD CD E8 65 6C 00 D0 3E 6C 00 
    {4638} normal block at 0x006C4050, 24 bytes long.
     Data: <(H      (el  ?l > 28 48 0A 01 CD CD CD CD 28 65 6C 00 90 3F 6C 00 
    {4637} normal block at 0x006C4110, 24 bytes long.
     Data: <(H      hdl P@l > 28 48 0A 01 CD CD CD CD 68 64 6C 00 50 40 6C 00 
    {4636} normal block at 0x006C41D0, 24 bytes long.
     Data: <(H       cl  Al > 28 48 0A 01 CD CD CD CD A8 63 6C 00 10 41 6C 00 
    {4635} normal block at 0x006C4290, 24 bytes long.
     Data: <(H       bl  Al > 28 48 0A 01 CD CD CD CD E8 62 6C 00 D0 41 6C 00 
    {4634} normal block at 0x006C4350, 24 bytes long.
     Data: <(H      (bl  Bl > 28 48 0A 01 CD CD CD CD 28 62 6C 00 90 42 6C 00 
    {4633} normal block at 0x006C5510, 24 bytes long.
     Data: <(H      hal PCl > 28 48 0A 01 CD CD CD CD 68 61 6C 00 50 43 6C 00 
    {4632} normal block at 0x006C55D0, 24 bytes long.
     Data: <(H       `l  Ul > 28 48 0A 01 CD CD CD CD A8 60 6C 00 10 55 6C 00 
    {4631} normal block at 0x006C5690, 24 bytes long.
     Data: <(H       _l  Ul > 28 48 0A 01 CD CD CD CD E8 5F 6C 00 D0 55 6C 00 
    {4630} normal block at 0x006C5750, 24 bytes long.
     Data: <(H      (_l  Vl > 28 48 0A 01 CD CD CD CD 28 5F 6C 00 90 56 6C 00 
    {4629} normal block at 0x006C5810, 24 bytes long.
     Data: <(H      h^l PWl > 28 48 0A 01 CD CD CD CD 68 5E 6C 00 50 57 6C 00 
    {4628} normal block at 0x006C58D0, 24 bytes long.
     Data: <(H       ]l  Xl > 28 48 0A 01 CD CD CD CD A8 5D 6C 00 10 58 6C 00 
    {4627} normal block at 0x006C5990, 24 bytes long.
     Data: <(H       \l  Xl > 28 48 0A 01 CD CD CD CD E8 5C 6C 00 D0 58 6C 00 
    {4626} normal block at 0x006C5A50, 24 bytes long.
     Data: <(H      (\l  Yl > 28 48 0A 01 CD CD CD CD 28 5C 6C 00 90 59 6C 00 
    {4625} normal block at 0x006C5B10, 24 bytes long.
     Data: <(H       Zl PZl > 28 48 0A 01 CD CD CD CD A8 5A 6C 00 50 5A 6C 00 
    {4624} normal block at 0x006C5BD0, 24 bytes long.
     Data: <(H       Yl  [l > 28 48 0A 01 CD CD CD CD E8 59 6C 00 10 5B 6C 00 
    {4623} normal block at 0x006C5C90, 24 bytes long.
     Data: <(H      (Yl  [l > 28 48 0A 01 CD CD CD CD 28 59 6C 00 D0 5B 6C 00 
    {4622} normal block at 0x006C5D50, 24 bytes long.
     Data: <(H      hXl  \l > 28 48 0A 01 CD CD CD CD 68 58 6C 00 90 5C 6C 00 
    {4621} normal block at 0x006C5E10, 24 bytes long.
     Data: <(H       Wl P]l > 28 48 0A 01 CD CD CD CD A8 57 6C 00 50 5D 6C 00 
    {4620} normal block at 0x006C5ED0, 24 bytes long.
    

    Mal sehen, vllt gibt es nen anderes Tool für Speicherlecks, aber danke für die Hilfen 🙂



  • Ganz einfach: Du dumpst am Anfang deines Programms und nicht am Ende ;).
    Das ist des Rätsels Lösung.
    Davon abgesehen brauchst du diese Funktion gar nicht aufrufen.
    wxWidgets hat das schon automatisch eingebaut.

    Füge einfach irgendwo

    new int[5];
    

    ein und du wirst die Meldung über Lecks auch ohne den Aufruf bekommen.

    @Mechanics
    Man braucht die meisten allokierten Objekte in wxWidgets nicht selber löschen, da wxWidgets den Besitz dieser übernimmt. Das betrifft vor allem (Kind)Fenster. Daher ist deine Antwort hier leider nicht so ganz richtig.

    edit:
    Davon abgesehen, noch was zum Memory Leak Report von Visual Studio:

    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
    

    Schreib das am Anfang deines Programms und du brauchst _CrtDumpMemoryLeaks() nie aufrufen und Visual Studio meldet automatisch alle Memory Leaks.

    Beispiel:

    int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
    {
    	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    	_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
    
    	// Find Path of Executable
    	char path[MAX_PATH + 1];
    	GetModuleFileNameA(NULL, path, MAX_PATH + 1);
    	std::string realPath(path);
    	realPath = realPath.substr(0, realPath.find_last_of('\\')+1);
    
    	return Application::getInstance().run(realPath);
    }
    }
    

Anmelden zum Antworten