2016-12-30 17 views
25

Tôi đang cố gắng tìm ra số lượng bộ nhớ mà tôi có thể phân bổ trước khi phân bổ không thành công.Dung lượng bộ nhớ lớn nhất mà tôi có thể phân bổ trên MacBook Pro của mình là bao nhiêu?

Mã C++ đơn giản này cấp phát bộ đệm (có kích thước 1024 byte), gán cho năm ký tự cuối cùng của bộ đệm, báo cáo và sau đó xóa bộ đệm. Sau đó nó tăng gấp đôi kích thước của bộ đệm và lặp lại cho đến khi nó không thành công.

Trừ khi tôi thiếu thứ gì đó, mã có thể phân bổ tới 65 terabyte bộ nhớ trước khi nó không thành công trên MacBook Pro của tôi. Điều này thậm chí có thể? Làm thế nào nó có thể phân bổ bộ nhớ nhiều hơn tôi có trên máy? Tôi phải thiếu một cái gì đó đơn giản.

int main(int argc, char *argv[]) 
{ 
     long long size=1024; 
     long cnt=0; 
     while (true) 
     { 
       char *buffer = new char[size]; 
       // Assume the alloc succeeded. We are looking for the failure after all. 

       // Try to write to the allocated memory, may fail 
       buffer[size-5] = 'T'; 
       buffer[size-4] = 'e'; 
       buffer[size-3] = 's'; 
       buffer[size-2] = 't'; 
       buffer[size-1] = '\0'; 

       // report 
       if (cnt<10) 
         cout << "size[" << cnt << "]: " << (size/1024.) << "Kb "; 
       else if (cnt<20) 
         cout << "size[" << cnt << "]: " << (size/1024./1024.) << "Mb "; 
       else 
         cout << "size[" << cnt << "]: " << (size/1024./1024./1024.) << "Gi "; 
       cout << "addr: 0x" << (long)buffer << " "; 
       cout << "str: " << &buffer[size-5] << "\n"; 

       // cleanup 
       delete [] buffer; 

       // double size and continue 
       size *= 2; 
       cnt++; 
     } 
     return 0; 
} 
+1

là phân bổ các biến trên bộ nhớ "Bộ nhớ truy cập ngẫu nhiên" hoặc trên "Đĩa cứng"? – Raindrop7

+3

BTW: Nếu bạn thực sự cố gắng xác định mức tối đa thực tế bạn có thể phân bổ, bạn sẽ có vòng lặp bổ sung được sử dụng sau lần thất bại đầu tiên trong đó bạn giảm số tiền được thêm vào yêu cầu phân bổ của mình theo hệ số hai lần cho đến khi bạn tăng mức tối thiểu bạn muốn kiểm tra. Ví dụ: yêu cầu cho 512GiB là OK, yêu cầu cho 1024GiB không thành công, sau đó yêu cầu (512GiB + 256GiB) = 768GiB (nếu OK sau đó (768GiB + 128GiB) = 896GiB, nếu thất bại thì thử (512GiB + 128GiB) = 640GiB), v.v. – Makyen

+4

macbook pro hay không là không thích hợp ở đây, bạn không cần phải đặt nó trong tiêu đề. [Phân bổ nhiều bộ nhớ hơn so với tồn tại bằng cách sử dụng malloc] (http://stackoverflow.com/q/19750796/995714), [bộ nhớ tối đa mà malloc có thể phân bổ] (http://stackoverflow.com/q/2798330/995714) –

Trả lời

44

Khi bạn yêu cầu bộ nhớ, hệ điều hành có quyền không thực sự cho bạn nhớ rằng cho đến khi bạn thực sự sử dụng nó.

Đó là những gì đang xảy ra ở đây: bạn chỉ sử dụng 5 byte. ZX81 của tôi từ những năm 1980 có thể xử lý điều đó.

+0

Tôi sử dụng nó. Tôi ghi dữ liệu vào năm ký tự cuối cùng của bộ đệm và sau đó in nó. –

+27

Vì vậy, những gì, hệ điều hành là thông minh hơn bạn nghĩ. Bạn không nghĩ rằng một macbook pro chỉ đơn giản là đẹp trai? – Bathsheba

+3

Oh. Vì vậy, nếu tôi đã viết cho mỗi nhân vật trong mỗi bộ đệm nó sẽ thất bại sớm hơn nhiều? Đó là những gì bạn đang nói? –

35

MacOS X, giống như hầu hết mọi hệ điều hành hiện đại, sử dụng "phân bổ trễ" cho bộ nhớ. Khi bạn gọi new, hệ điều hành không thực sự phân bổ bất kỳ bộ nhớ nào. Nó chỉ đơn giản là làm cho một lưu ý rằng chương trình của bạn muốn một số tiền nhất định của bộ nhớ, và khu vực bộ nhớ mà bạn muốn bắt đầu tại một địa chỉ nhất định. Bộ nhớ chỉ thực sự được cấp phát khi chương trình của bạn cố gắng sử dụng nó.

Hơn nữa, bộ nhớ được phân bổ trong các đơn vị được gọi là "trang". Tôi tin rằng MacOS X sử dụng các trang 4kb, vì vậy khi chương trình của bạn ghi vào cuối bộ đệm, hệ điều hành sẽ cung cấp cho bạn 4096 byte ở đó, trong khi vẫn giữ phần còn lại của bộ đệm đơn giản là "chương trình của bạn muốn ghi nhớ".

Vì lý do bạn đạt đến giới hạn ở mức 64 terabyte, đó là do bộ vi xử lý x86-64 hiện tại sử dụng địa chỉ 48 bit. Điều này cung cấp cho 256 TB không gian địa chỉ, được chia đều giữa hệ điều hành và chương trình của bạn. Tăng gấp đôi phân bổ 64 TB sẽ chính xác phù hợp với 128 TB của chương trình của bạn một nửa không gian địa chỉ, ngoại trừ việc chương trình đã chiếm một chút của nó.

+2

Họ sử dụng thêm 16 bit của một địa chỉ để làm gì? – tbodt

+8

@tbodt - Chúng không. Về cơ bản, đó là * về mặt lý thuyết * một không gian địa chỉ 64 bit, nhưng vì lý do bố trí, 16 bit trên không sẵn sàng, bởi vì chip không thể hỗ trợ về mặt vật lý nhiều bộ nhớ. Điều đó làm cho thiết kế silicon dễ dàng hơn bởi vì bạn không có những phần xe buýt lớn đi khắp mọi nơi, nhưng không thực sự làm bất cứ điều gì. –

+8

Lưu ý rằng Windows cũng bị trì hoãn phân bổ, * nhưng nó không làm quá tải *, vì vậy trên Windows bạn không nên phân bổ nhiều hơn tổng dung lượng RAM + hoán đổi của bạn - bộ nhớ đã được sử dụng. – immibis

6

Virtual memory là chìa khóa để phân bổ nhiều không gian địa chỉ hơn so với RAM của bạn + không gian hoán đổi.

malloc sử dụng cuộc gọi hệ thống mmap(MAP_ANONYMOUS) để nhận các trang từ hệ điều hành. (Giả sử OS X hoạt động giống như Linux, vì chúng đều là hệ điều hành POSIX). Các trang này là tất cả bản sao ghi trên bản đồ được ánh xạ tới một trang không có vật lý. tức là tất cả họ đều đọc là số 0 chỉ với một lỗi TLB (không có lỗi trang và không phân bổ RAM vật lý). Trang là 4kiB. (Tôi không đề cập đến hugepages bởi vì họ không có liên quan ở đây).

Việc ghi vào bất kỳ trang nào trong số các trang đó sẽ kích hoạt một lỗi trang mềm để hạt nhân xử lý việc sao chép ghi. Hạt nhân cấp phát một trang không có bộ nhớ của bộ nhớ vật lý và kết nối lại rằng trang ảo được hỗ trợ bởi trang vật lý. Khi trở về từ lỗi trang, cửa hàng được thực hiện lại và thành công lần này.

Vì vậy, sau khi phân bổ 64TiB và lưu 5 byte vào cuối, bạn đã sử dụng thêm một trang bộ nhớ vật lý. (Và thêm một mục vào dữ liệu sổ sách kế toán của malloc, nhưng điều đó có thể đã được phân bổ và trong một trang bẩn. Trong một câu hỏi tương tự về nhiều phân bổ nhỏ, malloc's bookkeeping data was what eventually used up all the space).

Nếu bạn thực sự làm bẩn nhiều trang hơn hệ thống có RAM + hoán đổi, hạt nhân sẽ gặp sự cố vì đã quá muộn để malloc trả về NULL.Điều này được gọi là "overcommit" và một số hệ điều hành bật theo mặc định trong khi một số khác thì không. Trong Linux, nó có thể cấu hình được.


Vì đánh dấu giải thích, bạn hết hơi ở 64TiB vì hiện tại x86-64 chỉ hỗ trợ địa chỉ ảo 48 bit. 16 bit trên cần phải là bản sao của bit 47. (nghĩa là địa chỉ chỉ là chuẩn nếu giá trị 64 bit là phần mở rộng dấu của 48 bit thấp).

Yêu cầu này ngăn các chương trình làm bất cứ điều gì "thông minh" với các bit cao và sau đó phá vỡ phần cứng trong tương lai, hỗ trợ không gian địa chỉ ảo lớn hơn.

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