Ungewöhnliche Heap-Größenbeschränkungen in VS2003 C ++

Ich besitze eine C ++ - App, die große Datenmengen verwendet, und habe beim Testen festgestellt, dass der Arbeitsspeicher knapp wird, obwohl noch genügend Arbeitsspeicher verfügbar ist. Ich habe den Code wie folgt auf einen Beispieltestfall reduziert.

void    MemTest()
{
    size_t Size = 500*1024*1024;  // 512mb
    if (Size > _HEAP_MAXREQ)
        TRACE("Invalid Size");
    void * mem = malloc(Size);
    if (mem == NULL)
        TRACE("allocation failed");

}

Wenn ich ein neues MFC-Projekt erstelle, diese Funktion einbinde und in InitInstance ausführe, funktioniert sie im Debug-Modus (Speicher wird wie erwartet zugewiesen) einwandfrei, schlägt jedoch im Release-Modus fehl (malloc gibt NULL zurück). Wenn ich einmal durch die Freigabe in die C-Laufzeiten gehe, wird meine Funktion eingeblendet. Ich erhalte Folgendes

// malloc.c

void * __cdecl _malloc_base (size_t size)

{
        void *res = _nh_malloc_base(size, _newmode);

        RTCCALLBACK(_RTC_Allocate_hook, (res, size, 0));

        return res;
}

Aufruf von _nh_malloc_base

void * __cdecl _nh_malloc_base (size_t size, int nhFlag)
{
        void * pvReturn;

        //  validate size
        if (size > _HEAP_MAXREQ)
            return NULL;
'
'

Und (size> _HEAP_MAXREQ) gibt true zurück und daher wird mein Speicher nicht zugewiesen. Wenn Sie die Größe überprüfen, werden die erwarteten 512 MB zurückgegeben, was darauf hindeutet, dass das Programm eine Verknüpfung zu einer anderen Laufzeitbibliothek mit einem viel kleineren _HEAP_MAXREQ herstellt. Wenn ich die VC ++ - Ordner nach _HEAP_MAXREQ durchsuche, wird die erwartete 0xFFFFFFE0 angezeigt, sodass ich nicht herausfinden kann, was hier passiert. Kennt jemand irgendwelche CRT-Änderungen oder -Versionen, die dieses Problem verursachen könnten, oder fehle ich etwas, das viel offensichtlicher ist?

Bearbeiten: Wie von Andreas vorgeschlagen, zeigt ein Blick auf diese Baugruppenansicht Folgendes:

--- f:\vs70builds\3077\vc\crtbld\crt\src\malloc.c ------------------------------
_heap_alloc:
0040B0E5  push        0Ch  
0040B0E7  push        4280B0h 
0040B0EC  call        __SEH_prolog (40CFF8h) 
0040B0F1  mov         esi,dword ptr [size] 
0040B0F4  cmp         dword ptr [___active_heap (434660h)],3 
0040B0FB  jne         $L19917+7 (40B12Bh) 
0040B0FD  cmp         esi,dword ptr [___sbh_threshold (43464Ch)] 
0040B103  ja          $L19917+7 (40B12Bh) 
0040B105  push        4    
0040B107  call        _lock (40DE73h) 
0040B10C  pop         ecx  
0040B10D  and         dword ptr [ebp-4],0 
0040B111  push        esi  
0040B112  call        __sbh_alloc_block (40E736h) 
0040B117  pop         ecx  
0040B118  mov         dword ptr [pvReturn],eax 
0040B11B  or          dword ptr [ebp-4],0FFFFFFFFh 
0040B11F  call        $L19916 (40B157h) 
$L19917:
0040B124  mov         eax,dword ptr [pvReturn] 
0040B127  test        eax,eax 
0040B129  jne         $L19917+2Ah (40B14Eh) 
0040B12B  test        esi,esi 
0040B12D  jne         $L19917+0Ch (40B130h) 
0040B12F  inc         esi  
0040B130  cmp         dword ptr [___active_heap (434660h)],1 
0040B137  je          $L19917+1Bh (40B13Fh) 
0040B139  add         esi,0Fh 
0040B13C  and         esi,0FFFFFFF0h 
0040B13F  push        esi  
0040B140  push        0    
0040B142  push        dword ptr [__crtheap (43465Ch)] 
0040B148  call        dword ptr [__imp__HeapAlloc@12 (425144h)] 
0040B14E  call        __SEH_epilog (40D033h) 
0040B153  ret              
$L19914:
0040B154  mov         esi,dword ptr [ebp+8] 
$L19916:
0040B157  push        4    
0040B159  call        _unlock (40DDBEh) 
0040B15E  pop         ecx  
$L19929:
0040B15F  ret              
_nh_malloc:
0040B160  cmp         dword ptr [esp+4],0FFFFFFE0h 
0040B165  ja          _nh_malloc+29h (40B189h) 

Mit den Registern wie folgt;

EAX = 009C8AF0 EBX = FFFFFFFF ECX = 009C8A88 EDX = 00747365 ESI = 00430F80 EDI = 00430F80 EIP = 0040B160 ESP = 0013FDF4 EBP = 0013FFC0 EFL = 00000206

Der Vergleich scheint also mit der korrekten Konstante zu sein, d.h.

Zweite Bearbeitung: Problem war eigentlich in HeapAlloc, laut Andreas Beitrag. Der Wechsel zu einem neuen separaten Heap für große Objekte mithilfe von HeapCreate & HeapAlloc hat weder zur Behebung des Problems beigetragen, noch wurde versucht, VirtualAlloc mit verschiedenen Parametern zu verwenden. Einige weitere Experimente haben gezeigt, dass, wenn die Zuweisung eines großen Abschnitts des zusammenhängenden Speichers fehlschlägt, zwei kleinere Blöcke, die den gleichen Gesamtspeicher ergeben, in Ordnung sind. z.B. Wenn ein 300-MB-Malloc ausfällt, funktionieren 2 x 150-MB-Mallocs einwandfrei. Es sieht also so aus, als würde ich eine neue Array-Klasse brauchen, die in mehreren großen Speicherfragmenten leben kann, anstatt in einem einzelnen zusammenhängenden Block. Kein großes Problem, aber ich hätte heute ein bisschen mehr von Win32 erwartet.

Letzte Änderung: Das folgende Beispiel ergab 1,875 GB Speicherplatz, wenn auch nicht zusammenhängend

#define TenMB 1024*1024*10

void    SmallerAllocs()
{

    size_t Total = 0;
    LPVOID  p[200];
    for (int i = 0; i < 200; i++)
    {
        p[i] = malloc(TenMB);
        if (p[i])
            Total += TenMB; else
            break;
    }
    CString Msg;
    Msg.Format("Allocated %0.3lfGB",Total/(1024.0*1024.0*1024.0));
    AfxMessageBox(Msg,MB_OK);
}

Antworten auf die Frage(1)

Ihre Antwort auf die Frage