首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >VS2003 C++中不寻常的堆大小限制

VS2003 C++中不寻常的堆大小限制
EN

Stack Overflow用户
提问于 2010-03-18 12:24:32
回答 1查看 2K关注 0票数 6

我有一个C++应用程序,它使用了大量的数据,并且在测试内存不足时注意到了这一点,而内存仍然是可用的。我将代码简化为一个示例测试用例,如下所示;

代码语言:javascript
运行
复制
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运行时的单步发布,我的函数将内联,我得到以下内容

代码语言:javascript
运行
复制
// 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

代码语言:javascript
运行
复制
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 on,这意味着这个程序连接到了一个不同的运行时库,它的_HEAP_MAXREQ要小得多。在VC++文件夹中为_HEAP_MAXREQ显示预期的0xFFFFFE0,所以我不知道这里发生了什么。有人知道任何CRT的改变或版本会导致这个问题,或者我是不是遗漏了一些更明显的东西?

编辑:如安德烈亚斯所建议的那样,在这个程序集视图下看这个,显示如下;

代码语言:javascript
运行
复制
--- 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 ECX = FFFFFFFF ECX= 009C8A88 EDX = 00747365 ESI = 00430F80 EDI = 00430F80 EIP = 0040B160 ESP =0013FDF4EBP=0013FC0EFL= 00000206

因此,这种比较似乎与正确的常数,即@040B160 cmp dword ptr esp+4,0FFFFFFE0h,以及esp+4 = 0013FDF8 = 1F400000 (我的512 my)相比较。

第二次编辑:根据Andreas的文章,问题实际上出现在HeapAlloc中。使用HeapCreate & HeapAlloc对大型对象更改为一个新的独立堆无助于缓解这个问题,也没有尝试使用各种参数的VirtualAlloc。一些进一步的实验表明,如果分配一个大段的连续内存失败,两个小块产生相同的总内存是可以的。例如,当一个300 ok的malloc失败时,2x150MB的mallocs工作正常。因此,看起来我需要一个新的数组类,它可以驻留在许多较大的内存片段中,而不是单个连续块中。这并不是一个大问题,但在这个时代,我希望Win32能有更多的发展。

最后一次编辑:获得了1.875GB的空间,尽管不是连续的

代码语言:javascript
运行
复制
#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);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2010-03-18 13:07:19

可能是调试器在发布模式中对你耍戏法吗?在发布模式下,单步执行和变量值都不可靠.

我在VS2003中尝试了发布模式下的示例,当单步执行时,它最初看起来就像是代码在return NULL行上着陆,但是当我继续前进时,我猜想是这个函数失败了,查看反汇编if (size > _HEAP_MAXREQ)显示了以下内容:

代码语言:javascript
运行
复制
00401078  cmp         dword ptr [esp+4],0FFFFFFE0h 

所以我不认为这是_HEAP_MAXREQ的问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2469738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档