2012-06-10 20 views
5

Chương trình sau bị hạt nhân giết khi bộ nhớ bị hết. Tôi muốn biết khi nào biến toàn cục nên được gán cho "ENOMEM".Khi nào nên không được gán cho ENOMEM?

#define MEGABYTE 1024*1024 
#define TRUE 1 
int main(int argc, char *argv[]){ 

    void *myblock = NULL; 
    int count = 0; 

    while(TRUE) 
    { 
      myblock = (void *) malloc(MEGABYTE); 
      if (!myblock) break; 
      memset(myblock,1, MEGABYTE); 
      printf("Currently allocating %d MB\n",++count); 
    } 
    exit(0); 
} 
+3

Cũng giống như thêm gợi ý. Không bỏ trả lại 'malloc'. Việc đưa nó vào 'void *' đặc biệt kỳ lạ vì đó * là * kiểu trả về. Nếu bạn cảm thấy cần thiết cho nó, bạn có thể quên bao gồm "stdlib.h". Sau đó, trình biên dịch C hiện đại (và trên Linux tất cả đều hiện đại theo nghĩa đó) có kiểu Boolean. Bao gồm "stdbool.h" và sử dụng 'bool',' false' và 'true' một cách thích hợp. –

Trả lời

4

Thứ nhất, sửa chữa kernel không overcommit:

echo "2" > /proc/sys/vm/overcommit_memory 

Bây giờ malloc nên cư xử đúng cách.

+0

+1, câu trả lời này là đúng, mặc dù nó không giải thích tại sao :) Để cung cấp cho bạn nhiều thông tin hơn về những gì đang xảy ra trên các hệ thống linux hiện đại, nếu bạn không làm những gì R .. gợi ý. Một phân bổ sau đó chỉ cần dự trữ một loạt các địa chỉ ảo cho quá trình và không phân bổ các trang của mình. Đây chỉ là thực sự yêu cầu từ hạt nhân khi bạn truy cập chúng lần đầu tiên. –

+0

Ngay cả với bản sửa lỗi của tôi, hạt nhân không tự phân bổ các trang ngay lập tức. Nó chỉ chiếm bao nhiêu là cần thiết và chắc chắn rằng không bao giờ cam kết nhiều hơn có thể (sau này) được thỏa mãn. –

+0

Điều này được quản lý để hoàn toàn phá vỡ hộp CentOS của tôi và yêu cầu khởi động lại:/ –

2

Điều này xảy ra khi bạn cố gắng phân bổ quá nhiều bộ nhớ cùng một lúc.

#include <stdlib.h> 
#include <stdio.h> 
#include <errno.h> 

int main(int argc, char *argv[]) 
{ 
    void *p; 

    p = malloc(1024L * 1024 * 1024 * 1024); 
    if(p == NULL) 
    { 
    printf("%d\n", errno); 
    perror("malloc"); 
    } 
} 

Trong trường hợp của bạn, kẻ giết người OOM đang bắt đầu quy trình.

+0

Có sự khác biệt nào giữa hai ví dụ về cơ bản không? –

+0

Bạn tăng tốc lên mức giới hạn, trong khi tôi vi phạm nó hoàn toàn. –

+0

Tôi không hiểu rõ. –

2

Tôi nghĩ errno sẽ được thiết lập để ENOMEM:

Macro quy định tại stdio.h. Đây là documentation.

#define ENOMEM   12  /* Out of Memory */ 

Sau khi bạn gọi malloc trong bản Tuyên Bố này:

myblock = (void *) malloc(MEGABYTE);

Và hàm trả về NULL -because hệ thống là ra khỏi bộ nhớ -.

Tôi tìm thấy this SO câu hỏi rất thú vị.

Hy vọng điều đó sẽ hữu ích!

2

Khi "R" được gợi ý, sự cố là hành vi mặc định của quản lý bộ nhớ Linux, điều này là "quá mức". Điều này có nghĩa rằng hạt nhân tuyên bố để cấp phát bộ nhớ cho bạn thành công, nhưng không thực sự cấp phát bộ nhớ cho đến sau này khi bạn cố truy cập nó. Nếu hạt nhân phát hiện ra rằng nó được cấp phát quá nhiều bộ nhớ, nó sẽ giết chết một quá trình với "kẻ giết người OOM (Out Of Memory)" để giải phóng bộ nhớ. Cách mà nó chọn quá trình giết rất phức tạp, nhưng nếu bạn chỉ phân bổ hầu hết bộ nhớ trong hệ thống, nó có thể sẽ là quá trình của bạn nhận được viên đạn.

Nếu bạn nghĩ điều này nghe có vẻ điên rồ, một số người sẽ đồng ý với bạn.

Để có được nó để hành xử như bạn mong đợi, như R nói:

echo "2" > /proc/sys/vm/overcommit_memory

+0

+1 cho "nếu bạn nghĩ rằng điều này nghe có vẻ điên rồ" .. :-) –

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