Speicherleck nach Umstellung auf VS2015 mit XP Support



  • Hallo,

    ich habe eine C++ Win32-API-Serveranwendung, die ich mit VS2015 kompiliere ich mit dem Windows XP (v140_xp) Toolset. Dieses Programm läuft unter Windows 7 super ohne Memory leak. Unter Windows XP läuft der Speicher des Programm beim Anlegen eines neuen Threads immer weiter hoch.

    Vor der Umstellung auf VS2015 mit VS2010 gab es dieses Problem mit dem Speicher auch nicht. Habe auch schon die Threads auf ein Minimum reduziert, so daß meine Vermutung darin besteht, dass der Aufruf des Threads mit _beginthreadex zu dem Memory Leak führt.

    Das Programm wird statisch gelinkt.

    Hat jemand eine Idee, wo das Problem bei XP zu suchen ist und auch wie man es umgeht.

    Rudolf



  • Hallo Rudi2016,

    ich würde das Programm mal mit Dr.Memory (http://drmemory.org/) untersuchen, um sicherzugehen, dass Deine Annahme korrekt ist.

    Ich würde davon ausgehen, dass _beginthreadex ein WinAPI Call ist, und somit doch eigentlich dieselbe Implementierung von Windows dahinter steckt, daher wundert mich die Aussage dass die VS2015/VS2010 Umstellung eine Auswirkung hatte.

    Es ist nur eine Idee in den Raum geschmießen, kenne mich in diesem Bereich kaum aus.

    Viele Grüße,



  • Bist du sicher dass das Programm unter Windows 7 nicht leakt?
    XP und Windows 7 zeigen z.T. unterschiedliche Werte was Speicherverbrauch angeht im Task-Manager an, bzw. nennen auch die identischen Werte unterschiedlich.

    => Kannst du das Leaken/Nicht-leaken mit einem nicht OS-abhängigen Tool wie z.B. Process Explorer verifizieren?

    Und weil du _beginthreadex schreibst...
    Machst du das Handle das du von _beginthreadex zurückbekommst auch brav wieder zu ( CloseHandle )?



  • Hallo,

    ja ich habe mir den Speicherverbrauch auch mit dem Process Explorer angeschaut. Unter Win7 kommt der Speicherverbauch nach kurzer Zeit zum Stillstand.

    Unter XP dagegen läuft der Speicher permanent hoch.

    Nach Ende eines Threads wird das Handle des Threads auch wieder geclosed.

    Rudolf



  • Rudi2016 schrieb:

    ja ich habe mir den Speicherverbrauch auch mit dem Process Explorer angeschaut. Unter Win7 kommt der Speicherverbauch nach kurzer Zeit zum Stillstand.

    Wie kommt man von der Beobachtung auf die Vermutung dass es am Win-API Call "_beginthreadex" liegen muss?

    Vielen Dank fürs aufschlauen.



  • Schau bitte erst einmal nach, ob das Problem tatsächlich von _beginthreadex verursacht wird. Dazu linkst Du testweise mal die DLL-Version der CRT und nicht die statische Version.

    Wenn es danach tatsächlich weg ist, sage ich Dir, wie Du das Problem beheben kannst. Wenn das Problem dann noch immer besteht, liegt es nicht an _beginthreadex.



  • jb schrieb:

    Wie kommt man von der Beobachtung auf die Vermutung dass es am Win-API Call "_beginthreadex" liegen muss?

    Seit wann ist _beginthreadex ein Win-API Call?

    Vielen Dank fürs aufschlauen.



  • Mox schrieb:

    Schau bitte erst einmal nach, ob das Problem tatsächlich von _beginthreadex verursacht wird. Dazu linkst Du testweise mal die DLL-Version der CRT und nicht die statische Version.

    Wenn es danach tatsächlich weg ist, sage ich Dir, wie Du das Problem beheben kannst. Wenn das Problem dann noch immer besteht, liegt es nicht an _beginthreadex.

    Jetzt ist es weg, was kann ich tun?



  • Du hast Aufrufe von ExitThread in Deinem Progrämmchen. Ab Vista ist das kein Problem mehr, aber eben unter XP. Verwende anstelle dessen die Funktion _endthreadex.

    Noch besser ist es meiner Meinung nach, auf sofortiges Abwürgen ganz zu verzichten. Ein einfaches return am Ende der ThreadProc reicht völlig aus.



  • Mox schrieb:

    jb schrieb:

    Wie kommt man von der Beobachtung auf die Vermutung dass es am Win-API Call "_beginthreadex" liegen muss?

    Seit wann ist _beginthreadex ein Win-API Call?

    Vielen Dank fürs aufschlauen.

    Hallo Mox,

    also ich vermute mal das diese Frage eher ironisch ist - oder? Dann kann ich darauf nichts antworten. Ich verstehe trotzdem nicht mit den gegeben Informationen, wie man ausgerechnet den Fehler auf "_beginthreadex" eingrenzen konnte. Aber gut spielt ja jetzt auch keine Rolle, war nur reines Interesse.

    Wenn ich mit meinem Bauchgefühl falsch liege, dann hier meine Antwort auf die Frage: Wir sind in einem WinAPI Unterforum, daher nehme ich an dass der Thread Ersteller weiß wo er es postet - da auch kein Moderator es verschoben hat - und somit ist das für mein dafürhalten ein Methodenaufruf von der WinAPI. (Call = Aufruf). Außer der Begriff Call ist in diesem Kontext anderweitig bereits belegt.

    Ein guten Wochenstart wünsche ich.



  • _beginthread und _beginthreadex sind aus der C Standardbibliothek und nicht aus der Windows API.



  • Was wäre das richtige Forum? Ich verwende kein MFC und greife sonst auch auf Win32API-Funktionen zu.

    Wie komme ich auf die _beginthreadex Funktion? Ganz einfach ich habe die Bearbeitungsroutinen komplett durch minimalen Dummycode ersetzt. Und greife jetzt mit mehreren Dummyclients auf den Server zu. Der Speicherverbrauch steigt je nach Zugriffshäufigkeit der Clients.

    Rudi



  • https://msdn.microsoft.com/de-de/library/windows/desktop/ms682659(v=vs.85).aspx
    Zitat:
    A thread in an executable that is linked to the static C run-time library (CRT) should use _beginthread and _endthread for thread management rather than CreateThread and ExitThread. Failure to do so results in small memory leaks when the thread calls ExitThread.



  • Danke für Info

    ich benutze ja aus diesem Grund _beginthreadex und beim Verlassen des Threads return. Wenn ich statt return _endthreadex verwende, ändert sich nichts am Verhalten des Speichers



  • Belli schrieb:

    Failure to do so results in small memory leaks when the thread calls ExitThread.

    Glücklicherweise stimmt das so pauschal nicht mehr. Die CRT hat sich dahin gehend verändert, als das sie den Pointer auf die Per-Thread Daten nicht mehr in einem TLS Slot speichert, sondern FLS verwendet. FlsAlloc nimmt einen Pointer auf eine Callback-Funktion, die aufgerufen wird, wenn der Thread beendet wurde. Und hier wird die CRT im Notfall die Daten auch wieder los.

    Das Problem besteht nur noch auf dem alten XP. Hier gibt es die Fls* Funktionen nicht, da bleibt dann nur der Weg über TLS.



  • Rudi2016 schrieb:

    ... und beim Verlassen des Threads return.

    Das ist sehr gut, nur leider wird diese Stelle nicht erreicht. Dein Thread endet bereits vorher auf einem anderen Wege.

    Ich fasse die Informationen, die ich herausgelesen habe, nochmal zusammen:
    * Ein und dasselbe statische Compilat leckt unter 7 nicht, wohl aber unter XP.
    * Stellst Du um auf die DLL-Version der CRT, löst sich das Problem auch unter XP.

    Damit ist es meines Empfindens nach unmöglich, dass der Thread per return oder _endthread/ex beendet wird.



  • Hallo

    ich habe es noch nicht auf die DLL_Version der CRT umgestellt, weil das ein riesiger Aufwand ist und es eine Firmenrichtlinie gibt, die Programme statisch zu linken. Hat auch mit der VS2010 Version problemlos geklappt.

    Wie gehe ich das Problem mit TLS an?


  • Mod

    Rudi2016 schrieb:

    Danke für Info

    ich benutze ja aus diesem Grund _beginthreadex und beim Verlassen des Threads return. Wenn ich statt return _endthreadex verwende, ändert sich nichts am Verhalten des Speichers

    Dann trifft es Dich auch nicht.

    _endthreadex muss man auch nicht aufrufen. Es genügt einfach ein return aus der Threadfunktion!



  • Gibt es denn nirgendwo einen Tipp wie ich dies Problem fixe. Eine Umstellung der Rechner auf Windows 7 ist nicht so schnell realisiierbar.

    So bleibt mir nur den Code und alle Libraries wieder mit Toolset VS2010 zu komplieren, dort tritt der Fehler nicht auf.

    Oder hat jemand eine andere Idee.

    Könnte eine Umstellung auf std::stread das Problem lösen oder verwendet std::thread auch _beginthreadex?


  • Mod

    Finde doch erstmal heraus was da leckt...



  • Hallo Martin,

    ich habe eine Server-Anwendung die Commands abarbeitet. Im Thread, der auf dem Serverport lauscht, verwendet _beginthreadex um die Commands abzuarbeiten.
    Ich habe bereits die Commands auf das Notwendigste reduziert. Auch dann tritt der Fehler auf. Man kann dann erkennen, dass genau dann wenn Commandanfragen kommen, der Speicher hochläuft.

    Ein Kollege, der einen anderen Server umgestellt hat, hat das Problem genauso.

    Ich bin jedenfalls mit meinem Latein am Ende, wo ich noch suchen soll. Oder kannst du Tools empfehlen?

    Gruß
    Rudi


Anmelden zum Antworten