2010-10-25 33 views
6
int *p; 
while(true) 
{ 
p = new int; 
} 

Do hết dung lượng bộ nhớ, mã này không bị lỗi. Tôi đã thử in ra giá trị của p, đó là địa chỉ của bộ nhớ nằm cho p, và nó có vẻ tăng nhưng chưa có sự cố.Không nên mã này gặp sự cố

Tại sao lại như vậy?

+9

Vâng, nội dung này không xảy ra ngay lập tức. Và đối với một phân bổ nhỏ như vậy, bạn sẽ chờ đợi một tiimmme looooong. – GManNickG

+7

Không, nó không thực sự sụp đổ. Cuối cùng 'new' sẽ ném một ngoại lệ và chấm dứt chương trình, mặc dù. Tùy thuộc vào hệ thống của bạn, có thể sau một vài tỷ vòng - không giữ hơi thở của bạn trên một hệ thống 64 bit với nhiều không gian trao đổi. Hãy thử xem việc sử dụng bộ nhớ của chương trình bằng cách sử dụng công cụ quản lý/ps/bất cứ điều gì. Nếu nó tăng lên, bạn sẽ thấy nhanh như thế nào. –

+0

Bạn có đang chạy trên hệ điều hành 64 bit không? –

Trả lời

9

Giải pháp này cũng giống như cố gắng để sụp đổ xe hơi tại một cột điện thoại xuống các đường phố trong khi lái xe 1MPH. Nó sẽ xảy ra cuối cùng nhưng nếu bạn muốn kết quả nhanh chóng, bạn cần tăng tốc độ một chút.

int *p; 
while (true) { 
    p = new int[1024*1024*1024]; 
} 

Câu trả lời của tôi mặc dù được dựa trên phân bổ bộ nhớ STL tiêu chuẩn. Có các trình phân bổ có sẵn khác mà chỉ cần trả lại NULL về phân bổ không thành công. Loại cấp phát sẽ không bao giờ gặp sự cố trong mã này vì việc phân bổ không thành công không được coi là gây tử vong. Bạn sẽ phải kiểm tra sự trở lại của phân bổ cho NULL để phát hiện lỗi.

Một lưu ý khác, nếu bạn đang chạy trên hệ thống 64 bit, điều này có thể mất thời gian lâu hơn đáng kể do kích thước không gian địa chỉ tăng lên. Thay vì cuộc thăm dò qua điện thoại đang ở trên đường, nó trên khắp đất nước.

+0

Tôi nhận được hình ảnh, nhưng ngay cả khi tôi gõ bình luận này, không có tai nạn. –

+1

@Gunner, điều đó rất kỳ quặc. Bạn đang sử dụng phân bổ ném STL tiêu chuẩn? – JaredPar

+0

câu hỏi hay, tôi đã đề cập rằng trong các ý kiến ​​ở trên, nếu bạn đang sử dụng phiên bản mới của phiên bản mới thì bạn cần kiểm tra khi nào trả về null mới, lúc đó ném ngoại lệ của riêng bạn. Phiên bản mới của phiên bản mới sẽ trả về một con trỏ null thay vì ném một ngoại lệ. – pstrjds

4

Bạn không đợi đủ lâu.

[Nếu bạn muốn xem nó đang tiến triển như thế nào, hãy thêm một số đầu ra trên mỗi vòng 1000000 hoặc một thứ gì đó tương tự. Nó sẽ cuối cùng không thành công.]

+0

Tôi thực sự đã thử xuất ra giá trị của p, đó là địa chỉ của bộ nhớ p trỏ đến và tôi thấy nó tăng lên. –

+0

@Gunner - vâng, tôi đã nghĩ đến một chỉ số thô hơn để bạn có thể thấy khoảng thời gian cần thiết để phát triển. Một khi bạn nhấn vào pagefile, nó sẽ làm chậm ngay trên xuống. Đề nghị của @Steve Jessop trong ý kiến ​​để sử dụng một màn hình quá trình là một đặt cược tốt cho điều này mặc dù. –

7

Phân bổ cấp độ nhỏ của bộ nhớ nhỏ chậm hơn một phân bổ lớn. Ví dụ, nó sẽ mất nhiều thời gian hơn để phân bổ 4 byte 1 triệu lần, hơn 1 triệu byte 4 lần.

Cố gắng phân bổ khối lớn hơn bộ nhớ cùng một lúc:

int *p; 
while(true) 
{ 
p = new int[1024*1024]; 
} 
+2

Đó là một chút gây hiểu lầm. Việc cấp phát bộ nhớ của các đối tượng nhỏ không chậm hơn các đối tượng lớn. Nó chỉ mất nhiều lần lặp lại để hết bộ nhớ bằng cách sử dụng phân bổ nhỏ. – Ferruccio

+0

@Ferruccio Thật vậy. Tôi sẽ cố gắng để rephrase – KeatsPeeks

9

Hình như bạn sẽ không đóng câu hỏi này cho đến khi bạn nhìn thấy một vụ tai nạn :)

Trên Unix như hệ điều hành bạn có thể hạn chế dung lượng bộ nhớ ảo có sẵn cho một quá trình sử dụng lệnh ulimit. Bằng cách đặt VM thành 1MB, tôi có thể xem kết quả mong muốn sau khoảng 5 giây:

$ ulimit -v $((1024*1024)) # set max VM available to process to 1 MB 

$ ulimit -v    # check it. 
1048576 

$ time ./a.out    # time your executable. 
terminate called after throwing an instance of 'St9bad_alloc' 
    what(): std::bad_alloc 
Aborted 

real 0m5.502s 
user 0m4.240s 
sys 0m1.108s 
1

Tôi nghĩ rằng trình biên dịch đang thực hiện tối ưu hóa và không phân bổ bộ nhớ. Tôi chạy các ví dụ trên (bằng cách sử dụng valgrind) một số lần và thấy rằng mặc dù có nơi phân bổ, tất cả các nơi của bộ nhớ 0 byte.

Hãy thử điều này và chương trình của bạn sẽ bị giết (ít nhất là trên unix):

#include <cstdio> 

int main() { 

int *p; 

while (true) { 
     p = new int[1024*1024]; 
     p[0] = 0; 
     printf("%p\n",p); 
     for(unsigned j = 1; j < 1024*1024; j++) { 
       p[j] = p[j-1] + 1; 
     } 
} 

return 0; 
} 

Bạn thấy sự khác biệt duy nhất là tôi sử dụng bộ nhớ được phân bổ.

Vì vậy, nó không thực sự sụp đổ vì tôi đoán hệ điều hành đang ngăn quá trình từ đâm bằng cách chỉ cần giết nó (Không chắc chắn 100% về điều này)

+0

Câu trả lời thú vị. Mất bao lâu để mã của bạn bị lỗi? –

+0

Khoảng một phút. – George

+0

Tôi đang thử trên các cửa sổ. Thậm chí phân bổ 1024 * 1024 * 1024 tại một thời điểm không gây ra sự cố trong một thời gian. Tôi đoán có phải đã có một số loại tối ưu hóa. –

1

Một khả năng khác: hầu hết các hệ điều hành sẽ thực hiện phân bổ lạc quan. Khi bạn malloc, nói, 500 MB, bộ nhớ đó có thể không thực sự được dành riêng cho đến khi chương trình của bạn thực sự cố gắng đọc hoặc ghi vào nó.

Linux đặc biệt nổi tiếng với bộ nhớ quá hứa hẹn và sau đó dựa vào kẻ giết người OOM (out-of-memory) để whack quá trình cố gắng thu thập trên lời hứa của hạt nhân.

+0

Điều này có thể là một lý do có thể, nhưng nó thực sự là trường hợp hệ điều hành sẽ chỉ hứa hẹn cho bộ nhớ và sau đó cung cấp nó khi thực sự cần thiết? –

+1

@Gunner: theo ít nhất một số hệ thống, cấu hình và trạng thái bộ nhớ ảo, vâng. Có một bài viết hay về một ví dụ trong Linux tại http://linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html –

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