2010-03-18 22 views
6

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); 
} 
+2

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? –

Trả lời

1

nó có thể là diễn viên mà trình gỡ lỗi đang chơi một thủ thuật trên bạn trong phiên bản chế độ? Không có bước đơn lẻ nào cũng không phải là giá trị của các biến đáng tin cậy trong chế độ phát hành.

Tôi đã thử ví dụ của bạn trong VS2003 ở chế độ phát hành và khi bước đầu tiên nó trông giống như mã được đặt trên đường dây return NULL, nhưng khi tôi tiếp tục bước cuối cùng tiếp tục vào HeapAlloc, tôi đoán đó là chức năng đó là thất bại, nhìn vào tháo if (size > _HEAP_MAXREQ) tiết lộ như sau:

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

vì vậy tôi không nghĩ rằng đó là một vấn đề với _HEAP_MAXREQ.

+0

Tôi đã thử truy tìm qua NULL trở về, và nhận được các resuls tương tự, với lỗi xảy ra trong ứng dụng gốc của tôi trong 'return HeapAlloc (_crtheap, 0, size);' trong malloc.c, về cơ bản cho thấy chương trình thử nghiệm của tôi bị thiếu sót. Tôi sẽ thử một chương trình thử nghiệm khác và đăng lại, vì sự cố vẫn xảy ra trong ứng dụng chính của tôi. –

+1

@Shane 512 MB có khá nhiều bộ nhớ, chắc chắn có khả năng bạn không có bộ nhớ * liền kề * này trong không gian địa chỉ ảo quá trình của bạn. (Phân bổ có thể đã được đặt theo một cách khác trong chế độ gỡ lỗi, giải thích lý do tại sao nó hoạt động ở đó). –

+0

Tôi tự mình đi đến kết luận đó. Tôi đã thử một chương trình thử nghiệm với 2 mallocs của 512MB mỗi, mà làm việc, trong khi ứng dụng của tôi đang cố gắng để phân bổ 2 khối 300mb và không. Tôi đoán rằng đây là phân mảnh heap liên quan, và tôi sẽ phải xem lại cách tôi sử dụng heap trong ứng dụng của mình. Cảm ơn vì tất cả những phản hồi. –

Các vấn đề liên quan