Tôi có ứng dụng C++ sử dụng mảng dữ liệu lớn và đã nhận thấy trong khi kiểm tra rằng nó sắp hết bộ nhớ, trong khi vẫn còn nhiều bộ nhớ khả dụng. Tôi đã giảm mã xuống một trường hợp thử nghiệm mẫu như sau;Giới hạn kích thước heap không bình thường trong 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");
}
Nếu tôi tạo một dự án MFC mới, bao gồm chức năng này, và chạy nó từ InitInstance, nó hoạt động tốt trong chế độ gỡ lỗi (bộ nhớ được phân bổ như mong đợi), nhưng thất bại trong chế độ phát hành (malloc trả về NULL). Độc bước qua phát hành vào thời điểm C chạy, chức năng của tôi được inlined tôi nhận được sau
// 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;
}
Calling _nh_malloc_base
void * __cdecl _nh_malloc_base (size_t size, int nhFlag)
{
void * pvReturn;
// validate size
if (size > _HEAP_MAXREQ)
return NULL;
'
'
Và (size> _HEAP_MAXREQ) trả về true và vì thế bộ nhớ của tôi không nhận được được phân bổ. Đặt một đồng hồ trên kích thước trở lại với 512MB đã được dò tìm, cho thấy chương trình đang liên kết với một thư viện thời gian chạy khác với một _HEAP_MAXREQ nhỏ hơn nhiều. Tham khảo các thư mục VC++ cho _HEAP_MAXREQ cho thấy 0xFFFFFFE0 được mong đợi, vì vậy tôi không thể tìm ra những gì đang xảy ra ở đây. Bất cứ ai biết về bất kỳ thay đổi CRT hoặc các phiên bản mà có thể gây ra vấn đề này, hoặc tôi thiếu một cái gì đó cách rõ ràng hơn?
Chỉnh sửa: Theo đề xuất của Andreas, xem xét điều này trong chế độ xem lắp ráp này cho thấy những điều sau đây;
--- 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 [[email protected] (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)
Với sổ đăng ký như sau;
EAX = 009C8AF0 EBX = FFFFFFFF ECX = 009C8A88 EDX = 00.747.365 ESI = 00430F80 EDI = 00430F80 EIP = 0040B160 ESP = 0013FDF4 EBP = 0013FFC0 EFL = 00000206
Vì vậy, so sánh không xuất hiện để chống lại hằng đúng , tức là @ 040B160 cmp dword ptr [esp + 4], 0FFFFFFE0h, cũng đặc biệt + 4 = 0013FDF8 = 1F400000 (512MB của tôi)
Second chỉnh sửa: vấn đề là thực sự trong HeapAlloc, theo bài Andreas'. Thay đổi thành heap riêng biệt mới cho các đối tượng lớn, sử dụng HeapCreate & HeapAlloc, không giúp giảm bớt vấn đề, cũng không cố gắng sử dụng VirtualAlloc với các tham số khác nhau. Một số thử nghiệm tiếp theo đã chỉ ra rằng khi phân bổ một phần lớn của bộ nhớ tiếp giáp không thành công, hai khối nhỏ hơn cho năng suất cùng một bộ nhớ là ok. ví dụ. nơi một malloc 300MB không thành công, 2 x 150MB mallocs hoạt động ok. Vì vậy, có vẻ như tôi sẽ cần một lớp mảng mới có thể sống trong một số mảng bộ nhớ lớn hơn là một khối liền kề duy nhất. Không phải là một vấn đề lớn, nhưng tôi đã mong đợi nhiều hơn một chút so với Win32 trong ngày và tuổi tác này.
chỉnh sửa cuối: Sau đây mang lại 1.875GB của không gian, mặc dù không tiếp giáp
#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);
}
Nếu bạn nhìn vào việc tháo gỡ, giá trị nào được sử dụng cho '_HEAP_MAXREQ' trong'> '-comparison? –