Daten Import Crash



  • HeyHo liebe Cpp-Community,

    ich habe ein schwerwiegendes Problem.
    Und zwar habe ich eine große 32-Bit-Anwendung vor mir liegen, welches unter Windows VisualC++ 2010 entwickelt wurde.

    Das Programm soll eine Datei öffnen, und daraufhin soll sie eine vergleichbare andere Datei dazu importieren, sprich ergänzen, damit ich daraufhin eine neue Datei habe, welches die Daten der alten Datei + die der neuen Datei enthält.

    Nun nach dem Ausführen des Programms habe ich irgendwann einen Assertion-Error bekommen, welches mich darauf hingewiesen hat, dass kein Speicher mehr reserviert werden kann.
    Daraufhin habe ich mir gedacht, dass ich eine Funktion in den Buffer schreibe, der mir ausgibt wieviel Speicher ich denn grad noch übrig habe. Und die lasse ich mir mithilfe einer 'XXX.log' Datei ausgeben.

    Funktion in C++ sieht wie folgt aus:

    //.....
    #include <windows.h>                                 
    #include <stdio.h>                                                              
    #define DIV 1024 
    
    //.....
    
    void VCommonBuffers::GetGlobalMemoryStatus(void)
    {
      MEMORYSTATUSEX statex;
      statex.dwLength = sizeof(statex);
      GlobalMemoryStatusEx(&statex);
    
      //Notiz: 'DBGWARNING' ist nur eine eigene Klasse für Warning-Ausgaben - Verhält sich wie 'cout'
    
      DBGWARNING("-----------------------------MEMORYSTATUS-------------------------------\n"
                 "There is  "  << statex.dwMemoryLoad << " percent of memory in use.\n"
                 "There is  "  << (100-statex.dwMemoryLoad) << " percent of memory not in use.\n"
                 "There are "  << statex.ullTotalPhys/DIV/DIV << " total MB of physical memory.\n"
                 "There are "  << statex.ullAvailPhys/DIV/DIV << " free MB of physical memory.\n"
                 "There are "  << statex.ullTotalPageFile/DIV/DIV << " total MB of paging file.\n"
                 "There are "  << statex.ullAvailPageFile/DIV/DIV << " free MB of paging file.\n"
                 "There are "  << statex.ullTotalVirtual/DIV/DIV << " total MB of virtual memory.\n"
                 "There are "  << statex.ullAvailVirtual/DIV/DIV << " free MB of virtual memory.\n"
                 "There are "  << statex.ullAvailExtendedVirtual/DIV/DIV << " free MB of extended memory.\n"
                 "------------------------------------------------------------------------");
    }
    

    Naja kommen wir zum eigentlich Hauptproblem. Vor und nach dem Ausführen krieg ich folgende Ausgaben:

    AUSGABE(VOR DEM START DES IMPORTS):
    -----------------------------MEMORYSTATUS-------------------------------
    There is 18 percent of memory in use.
    There is 82 percent of memory not in use.
    There are 12285 total MB of physical memory.
    There are 10025 free MB of physical memory.
    There are 30710 total MB of paging file.
    There are 28438 free MB of paging file.
    There are 4095 total MB of virtual memory.
    There are 3776 free MB of virtual memory.
    There are 0 free MB of extended memory.
    ------------------------------------------------------------------------

    AUSGABE(NACH EINIGER LAUFZEIT, LETZTE AUSGABE VOR DEM CRASH):
    -----------------------------MEMORYSTATUS-------------------------------
    There is 39 percent of memory in use.
    There is 61 percent of memory not in use.
    There are 12285 total MB of physical memory.
    There are 7450 free MB of physical memory.
    There are 30710 total MB of paging file.
    There are 25808 free MB of paging file.
    There are 4095 total MB of virtual memory.
    There are 154 free MB of virtual memory.
    There are 0 free MB of extended memory.
    ------------------------------------------------------------------------

    ...
    Bin sehr verzweifelt, ich verstehe nicht warum ein Crash verursacht wird,...
    immerhin gabs noch 154 MB im virtuellen Speicher, welches genutzt werden konnte... oder nicht?
    Ich hab mir gedacht ich hol mir hier im Forum noch einige Meinungen, man weiß ja nie
    vielleicht hat einer schon ein gleiches Problem gehabt, bzw. eine gute Idee/Tipp.

    (p.s.: Memory-Leaks sind ausgeschlossen, dafür wurde schon gesorgt, sprich 500000x getestet)^^

    vG, Kizane28!


  • Mod



  • Okey, da die Speicher Reservierung auch über Calloc/realloc folgt, werde ich mir das mal ganz genau unter die Lupe nehmen. Schonmal vielen Dank für diesen Tipp.
    Ich nehme gerne aber auch andere Tipps & Denkweise dankend an 🙂



  • Kurzer add zum Beitrag (Damit kein Missverständnis entsteht):
    Ich habe das mit dem Heap nochmal überprüft, kein Fehler, das steht fest.

    char *VCommonBuffers::GetCharBuffer(unsigned long nBytes)
    {
      if (static_cast<unsigned long>(mpCharBufferEnd - mpCharBufferStart) < nBytes) 
      {
        unsigned long nBufferBytes = static_cast<unsigned long>(mpCharBufferEnd-mpCharBufferStart);
    
        /*HIER WIRD VOR DEM ABSTURZ DER LETZTE MEMORYSTATUS AUSGEGEBEN*/
        GetGlobalMemoryStatus();    
    
        // guarantee new buffer is at least double the size of old buffer
        // (e.g. to avoid subsequent realloc for steadily increasing nBytes)
        nBytes = max(nBytes, nBufferBytes * 2);
        mpCharBufferStart = (char*) realloc(mpCharBufferStart, nBytes);
    
        /*HIER WIRD DER FEHLER ABGEFANGEN*/
        assert(mpCharBufferStart); // if not enough memory, no chance to continue
    
        mpCharBufferEnd = mpCharBufferStart + nBytes;
      }
      return mpCharBufferStart;
    }
    

    Damit man sich jetzt mehr darunter vorstellen kann...
    Wie reserviert sich Windows den Speicher?
    Kann es sein, dass z.B. 10MB gefordert werden, aber von den
    übrigen 154MB keine 10MB mehr am "STÜCK" vorhanden sind, und deswegen der Fehler kommt?
    (Ich hab ja keine Ahnung über die Arbeitsspeicherverwaltung und Arbeitsspeicherreservierung von Windows)



  • char *VCommonBuffers::GetCharBuffer(unsigned long nBytes)
    {
      if (static_cast<unsigned long>(mpCharBufferEnd - mpCharBufferStart) < nBytes)
      {
        unsigned long nBufferBytes = static_cast<unsigned long>(mpCharBufferEnd-mpCharBufferStart);
    
        /*HIER WIRD VOR DEM ABSTURZ DER LETZTE MEMORYSTATUS AUSGEGEBEN*/
        GetGlobalMemoryStatus();    
    
        // guarantee new buffer is at least double the size of old buffer
        // (e.g. to avoid subsequent realloc for steadily increasing nBytes)
        nBytes = max(nBytes, nBufferBytes * 2);
        mpCharBufferStart = (char*) realloc(mpCharBufferStart, nBytes);
    
        /*HIER WIRD DER FEHLER ABGEFANGEN*/
        assert(mpCharBufferStart); // if not enough memory, no chance to continue
    
        mpCharBufferEnd = mpCharBufferStart + nBytes;
      }
      return mpCharBufferStart;
    }
    

    Ähh, hat es einen Grund warum du keine STL benutzen willst? Verhindert Speicherlecks, also vermutlich genau dein Problem.

    Denn hier muss ich danz dumm fragen. Wer räumt denn den Rückgabewert char* auf? Wer ist zuständig für die Freigabe?

    Ansonsten schau dir mal mittels ProcessExplorer deinen Prozess (Working Set und Private Bytes) an. Mittels DebugDiag kann man übrigens Speicherfehler finden.



  • Bitte ein Bit schrieb:

    Ähh, hat es einen Grund warum du keine STL benutzen willst? Verhindert Speicherlecks, also vermutlich genau dein Problem.

    Denn hier muss ich danz dumm fragen. Wer räumt denn den Rückgabewert char* auf? Wer ist zuständig für die Freigabe?

    Ansonsten schau dir mal mittels ProcessExplorer deinen Prozess (Working Set und Private Bytes) an. Mittels DebugDiag kann man übrigens Speicherfehler finden.

    Ja der Grund ist, weil das mehr oder weniger so eine Schnittstelle zwischen Anwendung und den Steuergeräten ist...
    Da ist reines STL nicht drin,... da muss man auf etwas C zurückgreifen.

    Für die Freigabe sind mehrere andere Funktionen zuständig, aber die sollten alle passen, hab alles auch schon mit 'VisualLeakDetector' und anderen eigenen Softwaretest nach Memory Leaks abgesucht...
    Daher nehme ich an, dass keine Speicherlöcher entstehen.

    Meine Vermutung, ....
    kann es sein, dass Windows dich nicht auf 100% des virtuellen Memorys zugreifen lässt, da er z.B. sicherheitshalber 3% - 6% auf Reserve lässt?
    Und ich deswegen mit den 154MB schon an der Grenze bin?


  • Mod

    Schreib Dir doch mal etwas Code (nach Jeffrey Richter), dass Dir die Nutzung des aktuellen Prozesspeichers ausgibt.

    Wenn das nicht hilft schau Dir die Heaps mit WinDbg an.



  • Erneut vielen Dank für die fixen und doch sehr hilfreichen Antworten.
    Jeffrey Richter sagt mir zwar nichts, aber ich werd mich mal
    umgehend informieren und werde höchstwahrscheinlich direkt
    damit testen!


  • Mod

    Du kennst Jeffrey Richter "Advanced Windows" nicht? Dann hast Du was verpasst.

    Ich spiele auf VMMAP an... aber das geht teilweise auch in WinDbg!

    Es gibt auch das Sysinternals Tool!



  • Also erstmal sagt ja die Ausgabe des freien Speichers gar nichts über den freien virtuellen Speicher des Prozesses aus. Du hast ja eine 32Bit Anwendung, daher könnte es im ungünstigen Fall sein, dass dein Rechner von seinen 12GB Speicher noch 8GB Speicher frei hat, aber davon nichts mehr dem Prozess zur Verfügung gestellt werden kann, weil dieser seine 4GB Adressraum bereits nutzt.

    Es wäre daher viel interessanter mal mitzuloggen, wie groß der zusammenhängend angeforderte Speicherbereich ist.



  • Dein Speicherverbauch würde mich jetzt (wie andere auch) interresieren.

    Nicht dass du auf den Gedanken kommst sehr viel Speicher reservieren zu wollen obwohl du unter Win32 prinzipiell nur 2GByte zur Verfügung hast...



  • Morle schrieb:

    Also erstmal sagt ja die Ausgabe des freien Speichers gar nichts über den freien virtuellen Speicher des Prozesses aus. Du hast ja eine 32Bit Anwendung, daher könnte es im ungünstigen Fall sein, dass dein Rechner von seinen 12GB Speicher noch 8GB Speicher frei hat, aber davon nichts mehr dem Prozess zur Verfügung gestellt werden kann, weil dieser seine 4GB Adressraum bereits nutzt.

    Es wäre daher viel interessanter mal mitzuloggen, wie groß der zusammenhängend angeforderte Speicherbereich ist.

    Naja doch...
    Die Funktion 'GlobalMemoryStatusEx(&statex)' bezieht sich auf den
    virtuellen Adressraum des Prozesses, welches ihn aufruft.
    Sprich die 154MB freien Ressourcen gehören noch zu dem Adressraum
    meines Prozesses.



  • Bitte ein Bit schrieb:

    Dein Speicherverbauch würde mich jetzt (wie andere auch) interresieren.

    Nicht dass du auf den Gedanken kommst sehr viel Speicher reservieren zu wollen obwohl du unter Win32 prinzipiell nur 2GByte zur Verfügung hast...

    There are 3776 free MB of virtual memory //(Am Anfang)
    There are 154 free MB of virtual memory //(Am Ende)

    Speicherverbrauch: 3776-154 = 3622 MB
    Ca. Das wird mir auch von meinem 'ProzessExplorer' angezeigt.

    EDIT@Question: Kennt irgendjemand einen Programm, womit man die Speicherfragmentierung
    unter Windows beobachten kann? Ich habe die Vermutung, dass die 154MB
    nicht am Stück frei sind...

    So in etwa: ----++---+--+-+---++--+

    (- = Belegter Speicher)
    (+ = freier Speicher)

    in dem letzten Schritt, wo der Crash passiert werden 10MB angefordert, die dann nicht mehr allokiert werden können.

    Ich danke nochmals jedem für die Antworten in diesem Thread, hat schon
    wirklich einges gebracht und geholfen 🙂
    So langsam komm ich der ganzen Sache immer näher!


  • Mod

    Die Antwort habe ich Dir schon gegeben.
    VMMAP.
    Klick auf das Programm und schau Dir an was "Free" ist. Dor bekommst Du alle Segmente angezeigt...



  • Martin Richter schrieb:

    Die Antwort habe ich Dir schon gegeben.
    VMMAP.
    Klick auf das Programm und schau Dir an was "Free" ist. Dor bekommst Du alle Segmente angezeigt...

    --> Wird sofort gemacht!



  • Nun war es wirklich so,
    dass von den 154MB am Ende der längste freie Block nur noch 7,6MB war.
    Jedoch wurde am Ende nochmals versucht 10MB zu reservieren.
    -->VMMap ist ein Super mächtiges Tool
    (An dem Punkt HERZLICHSTEN Dank an "Martin Richter")

    Nun muss ich nur noch den Algorithmus für die Speicherreservierung ändern,
    aber das sollte dann auch weiter kein großes Problem mehr sein.
    (evtl mit 'placement new')

    Aber auch vielen dank an alle anderen Thread-Teilnehmer
    für eure Bemühungen!

    Gruß Kizane28! 🕶


  • Mod

    Bau Dein Tool unter 64bit 😉


Anmelden zum Antworten