2015-09-20 27 views
5

Tôi đang cố gắng thực hiện một mẫu bài tập C++ PL4 của Stroustrup. Nhiệm vụ là:không ném ngoại lệ bad_alloc

Phân bổ quá nhiều bộ nhớ bằng cách sử dụng newbad_alloc được ném. Báo cáo cách nhiều bộ nhớ được phân bổ và thời gian cần thiết. Thực hiện việc này hai lần: một lần không ghi vào bộ nhớ được cấp phát và sau khi viết thư cho từng thành phần .

Mã sau không ném một ngoại lệ std::bad_alloc. Sau khi tôi thực hiện chương trình, tôi nhận được thông báo "Bị giết" trong thiết bị đầu cuối.

Ngoài ra. Đoạn mã sau sẽ thoát sau ~ 4 giây. Nhưng khi tôi bỏ ghi chú thông báo sử dụng bộ nhớ

// ++i; 
// std::cout << "Allocated " << i*80 << " MB so far\n"; 

Chương trình sẽ chạy trong vài phút. Sau một thời gian nó in ra rằng terabyte bộ nhớ đã được cấp phát nhưng tôi không thấy nhiều thay đổi trong ứng dụng Màn hình hệ thống. Tại sao vậy?

Tôi sử dụng ứng dụng Linux và Màn hình hệ thống để xem tập quán.

#include <iostream> 
#include <vector> 
#include <chrono> 

void f() 
{ 
    std::vector<int*> vpi {}; 
    int i {}; 
    try{ 
     for(;;){ 
      int* pi = new int[10000]; 
      vpi.push_back(pi); 
      // ++i; 
      // std::cout << "Allocated " << i*80 << " MB so far\n"; 
     }  
    } 
    catch(std::bad_alloc){ 
     std::cerr << "Memory exhausted\n"; 
    } 
} 

int main() { 
    auto t0 = std::chrono::high_resolution_clock::now(); 
    f(); 
    auto t1 = std::chrono::high_resolution_clock::now(); 
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(t0-t1).count() << " ms\n"; 
} 
+0

Đầu ra sẽ mất * nhiều hơn * nhiều thời gian hơn so với phân bổ bộ nhớ đơn giản. Nếu nó chạy trong 2 phút, nó có thể là 1:56 cho đầu ra và vẫn còn 4 giây cho phân bổ. –

+0

Đó là trực giác của tôi. Nhưng tại sao nó in lại, giả sử, terabyte bộ nhớ đã được phân bổ cho đến nay? – tomtom

+0

có thể trùng lặp của [Một cách để xác định sử dụng bộ nhớ "thực" của quá trình, tức là RSS bẩn riêng tư?] (Http://stackoverflow.com/questions/118307/a-way-to-determine-a-processs-real- memory-usage-ie-private-dirty-rss) –

Trả lời

5

Trong thế giới tàn nhẫn hiện đại gọi new (cũng như malloc() hoặc thậm chí brk()) không nhất thiết phải cấp phát bộ nhớ. Nó chỉ gửi (thông qua một chuỗi các lớp) một yêu cầu tới một hệ điều hành và hệ điều hành gán một khu vực bộ nhớ ảo ảo (được làm tròn tới các trang bộ nhớ hệ thống). Vì vậy chỉ sau truy cập vào bộ nhớ đã cho mới thực hiện phân bổ thực tế.

Hơn nữa, các hệ điều hành hiện đại cho phép bộ nhớ "quá tải". Đôi khi (tùy thuộc vào hệ điều hành và các thiết lập của nó) các ứng dụng có thể yêu cầu bộ nhớ hoàn toàn hơn mà hệ điều hành có thể gán thậm chí về mặt lý thuyết, bao gồm tất cả các vùng trao đổi, v.v. Hãy xem ví dụ at this page.

Điều này được thực hiện bởi vì trong thực tế, một tình huống khi tất cả các ứng dụng thực sự sử dụng tất cả bộ nhớ được phân bổ trong cùng một lúc là hoàn toàn không thể xảy ra. Thường xuyên hơn, 99,99 ..% thời gian, các ứng dụng chỉ sử dụng một phần bộ nhớ của chúng và thực hiện theo trình tự, do đó, một hệ điều hành có cơ hội phục vụ các yêu cầu của chúng một cách liền mạch.

Để tăng cơ hội để thực sự gây ra lỗi phân bổ bộ nhớ, bạn có thể truy cập phần tử được phân bổ, nhưng một lần nữa tôi sẽ không gọi đó là bảo hành chính xác, chỉ "về khả năng tăng".

Trong trường hợp xấu nhất khi hệ điều hành thực sự thấy rằng nó không thể gán đủ bộ nhớ ảo vì quá nhiều ứng dụng đồng thời yêu cầu quyền truy cập vào dữ liệu được phân phối seamingly của họ, trình quản lý bộ nhớ OS khởi tạo một thủ tục đặc biệt được gọi là "OOM killer" mà chỉ đơn giản là giết chết các ứng dụng được chọn ngẫu nhiên (= ngẫu nhiên :)).

Vì vậy, dựa vào bad_alloc là một ý tưởng tồi hiện nay. Đôi khi bạn có thể nhận được một cách thực tế (ví dụ: khi giới hạn giả tạo ứng dụng của bạn với ulimit/setrlimit), nhưng nói chung, ứng dụng của bạn sẽ chạy trong môi trường không đảm bảo bất kỳ điều gì. Chỉ cần không phải là một con heo nhớ và cầu nguyện cho phần còn lại :)