VS2003 C ++中不正常的堆大小限制 [英] Unusual heap size limitations in VS2003 C++

查看:119
本文介绍了VS2003 C ++中不正常的堆大小限制的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个C ++应用程序,它使用大型数据数组,并注意到,当它运行内存不足,而仍有大量的内存可用。我已将代码缩减为一个示例测试用例,如下所示:

I have a C++ app that uses large arrays of data, and have noticed while testing that it is running out of memory, while there is still plenty of memory available. I have reduced the code to a sample test case as follows;

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返回NULL)。单步执行释放到C运行时间,我的函数得到内联我得到以下

If I create a new MFC project, include this function, and run it from InitInstance, it works fine in debug mode (memory allocated as expected), yet fails in release mode (malloc returns NULL). Single stepping through release into the C run times, my function gets inlined I get the following

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

Calling _nh_malloc_base

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

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

和(size> _HEAP_MAXREQ)返回true,内存不分配。将手表放在尺寸上返回512 MB,这表明该程序链接到一个具有更小_HEAP_MAXREQ的不同运行时库。为_HEAP_MAXREQ调整VC ++文件夹显示预期的0xFFFFFFE0,因此我无法确定这里发生了什么。任何人都知道任何CRT变化或版本会导致这个问题,或者我缺少一些更明显的方式。

And (size > _HEAP_MAXREQ) returns true and hence my memory doesn't get allocated. Putting a watch on size comes back with the exptected 512MB, which suggests the program is linking into a different run-time library with a much smaller _HEAP_MAXREQ. Grepping the VC++ folders for _HEAP_MAXREQ shows the expected 0xFFFFFFE0, so I can't figure out what is happening here. Anyone know of any CRT changes or versions that would cause this problem, or am I missing something way more obvious?

编辑 Andreas,在这个程序集视图下查看下面的内容:

As suggested by Andreas, looking at this under this assembly view shows the following;

--- 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 = 00747365 ESI = 00430F80
EDI = 00430F80 EIP = 0040B160 ESP = 0013FDF4 EBP = 0013FFC0 EFL = 00000206

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

所以比较似乎是对正确的常数,即@ 040B160 cmp dword ptr [esp + 4],0FFFFFFE0h,还有esp + 4 = 0013FDF8 = 1F400000(my 512mb)

So the compare does appear to be against the correct constant, i.e. @040B160 cmp dword ptr [esp+4],0FFFFFFE0h, also esp+4 = 0013FDF8 = 1F400000 (my 512mb)

第二个编辑:问题实际上是HeapAlloc,更改为大对象的新独立堆,使用HeapCreate& HeapAlloc,没有帮助缓解这个问题,也没有尝试使用VirtualAlloc与各种参数。一些进一步的实验已经表明,在分配一个大段连续存储器失败时,产生相同总存储器的两个较小块是确定的。例如其中300MB malloc失败,2 x 150MB mallocs工作正常。所以它看起来像我需要一个新的数组类,可以生活在一些biggish内存碎片,而不是一个单一的连续块。不是一个主要的问题,但我会期望一点点Win32在这一天和年龄。

Second edit: Problem was actually in HeapAlloc, as per Andreas' post. Changing to a new seperate heap for large objects, using HeapCreate & HeapAlloc, did not help alleviate the problem, nor did an attempt to use VirtualAlloc with various parameters. Some further experimentation has shown that where allocation one large section of contiguous memory fails, two smaller blocks yielding the same total memory is ok. e.g. where a 300MB malloc fails, 2 x 150MB mallocs work ok. So it looks like I'll need a new array class that can live in a number of biggish memory fragments rather than a single contiguous block. Not a major problem, but I would have expected a bit more out of Win32 in this day and age.

上次修改:以下产生1.875GB的空间,虽然不连续

Last edit: The following yielded 1.875GB of space, albeit non-contiguous

#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);
}


推荐答案

调试器是在释放模式下玩你的伎俩?

May it be the cast that the debugger is playing a trick on you in release-mode? Neither single stepping nor the values of variables are reliable in release-mode.

我在VS2003的发布模式下试过你的例子,当单步执行时,它首先看起来像代码正在着陆在 return NULL 行,但是当我继续步进它最终继续进入 HeapAlloc ,我猜这是这个函数失败,看看反汇编 if(size> _HEAP_MAXREQ)揭示以下内容:

I tried your example in VS2003 in release mode, and when single stepping it does at first look like the code is landing on the return NULL line, but when I continue stepping it eventually continues into HeapAlloc, I would guess that it's this function that's failing, looking at the disassembly if (size > _HEAP_MAXREQ) reveals the following:

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

我不认为这是 _HEAP_MAXREQ 的问题。

这篇关于VS2003 C ++中不正常的堆大小限制的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆