Необычные ограничения размера "кучи" в C++ VS2003

У меня есть приложение C++, которое использует большие массивы данных и заметило при тестировании этого, они исчерпывают память, в то время как существует все еще много доступной памяти. Я уменьшил код до демонстрационного тестового сценария следующим образом;

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");

}

Если я создаю новый проект MFC, включаю эту функцию и выполняю ее из InitInstance, она хорошо работает в режиме отладки (память, выделенная как ожидалось), все же сбои в режиме выпуска (malloc возвращает ПУСТОЙ УКАЗАТЕЛЬ). Единственное продвижение посредством выпуска во время выполнения C, моя функция встраивается, я получаю следующее

// 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;
}

Вызов _nh_malloc_base

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

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

И (размер> _HEAP_MAXREQ) возвращает true, и следовательно моя память не становится выделенной. Помещение часов на размере возвращается с exptected 512 МБ, который предполагает, что программа связывается в другую библиотеку времени выполнения с намного меньшим _HEAP_MAXREQ. Grepping, который папки VC ++ для _HEAP_MAXREQ показывают ожидаемому 0xFFFFFFE0, таким образом, я не могу выяснить то, что происходит здесь. Кто-либо знает о каких-либо изменениях CRT или версиях, которые вызвали бы эту проблему, или я пропускаю что-то более очевидный путь?

Править: Как предложил Andreas, смотря на это при этом представлении блока показывает следующее;

--- 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) 

С регистрами следующим образом;

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

Таким образом, сравнивание, действительно кажется, против корректной константы, т.е. @040B160 cmp dword ptr [esp+4], 0FFFFFFE0h, также esp+4 = 0013FDF8 = 1F400000 (мои 512 МБ)

Второе редактирование: проблема была на самом деле в HeapAlloc согласно сообщению Andreas. Изменение на новую отдельную "кучу" для больших объектов, использование HeapCreate & HeapAlloc, не помогли облегчить проблему, ни сделали попытку использовать VirtualAlloc с различными параметрами. Некоторое дальнейшее экспериментирование показало это, где выделение один большой раздел непрерывных сбоев памяти, два меньших блока, приводящие к той же общей памяти, в порядке. например, где 300 МБ malloc сбои, 2 x 150 МБ mallocs работают хорошо. Таким образом, похоже, что мне будет нужен новый класс массива, который может жить во многих великоватых фрагментах памяти, а не единственном непрерывном блоке. Не основная проблема, но я ожидал бы немного больше из Win32 в этот день и возраста.

Последнее редактирование: следующие 1.875 ГБ, к которым приводят, пространства, хотя, состоящий из нескольких несмежных участков,

#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);
}
6
задан SmacL 19 March 2010 в 12:23
поделиться

1 ответ

Может ли быть такое, что отладчик разыгрывает вас в режиме release? Ни одиночный шаг, ни значения переменных не являются надежными в release-режиме.

Я попробовал ваш пример в VS2003 в режиме release, и при одиночном шаге сначала кажется, что код приземляется на строке return NULL, но когда я продолжаю шаг, он в конце концов продолжается в HeapAlloc, я бы предположил, что именно эта функция дает сбой, если посмотреть на дизассемблер if (size > _HEAP_MAXREQ) и увидеть следующее:

00401078  cmp         dword ptr [esp+4],0FFFFFFE0h 

поэтому я не думаю, что это проблема с _HEAP_MAXREQ.

1
ответ дан 17 December 2019 в 22:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: