函数不会引发bad_alloc异常 [英] function doesn't throw bad_alloc exception

查看:169
本文介绍了函数不会引发bad_alloc异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试练习Stroustrup的C ++ PL4书.任务是:

使用new分配了太多的内存,导致抛出了bad_alloc.报告如何 分配了多少内存以及花费了多少时间.这样做两次: 一次不写入分配的内存,一次写入每个 元素.

以下代码不会引发std::bad_alloc异常.执行该程序后,我在终端收到消息"Killed".

也.以下代码将在约4秒钟后退出.但是,当我取消注释内存使用情况消息

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

程序将运行几分钟.一段时间后,它会打印出已分配了数TB的内存,但是我在System Monitor应用程序中看不到太大的变化.为什么呢?

我使用Linux和System Monitor应用程序查看用法.

#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";
}

解决方案

在现代残酷的世界中,调用new(以及malloc()甚至brk())并不一定会分配内存.它只是(通过一系列链)向操作系统发送请求,然后操作系统分配一个虚拟内存区域(四舍五入到系统内存页面).因此,只有随后对给定内存的访问才执行实际分配.

此外,现代OS允许内存过量使用".有时(取决于操作系统及其设置),应用程序可能需要更多的内存,甚至操作系统理论上也可以分配更多的内存,包括其所有交换区域等,而没有任何可见的问题.例如,在此页面上 .

之所以这样做,是因为在现实生活中,所有应用程序实际上将同时使用所有已分配的内存 的情况是不可能的.在99.99 ..%的时间中,应用程序更频繁地仅使用其内存的一部分,然后依次使用,因此操作系统有机会无缝地处理其请求.

增加机会以实际引起内存分配错误,您可以访问刚刚分配的元素,但是我不会将其称为逐字保证,只是关于增加可能性".

在最坏的情况下,当这样的操作系统实际上发现它无法分配足够的(虚拟)内存,因为太多的应用程序同时请求访问其分配的数据时,操作系统内存管理器会启动一个称为"OOM Killer"的特殊过程,该过程只是试探性地(=随机地:)杀死选定的应用程序.

因此,现在依赖bad_alloc是个坏主意.有时,您确实可以收到它(例如,当使用 ulimit/setrlimit 来人为限制您的应用程序时)通常,您的应用程序将在无法保证任何事情的环境中运行.只是不要成为记忆中的猪,为其余的祈祷:)

I'm trying to do an exercise form Stroustrup's C++PL4 book. The task is:

Allocate so much memory using new that bad_alloc is thrown. Report how much memory was allocated and how much time it took. Do this twice: once not writing to the allocated memory and once writing to each element.

The following code doesn't throw a std::bad_alloc exception. After I execute the program I get message "Killed" in terminal.

Also. The following code exits in ~4 seconds. But when I uncomment memory usage message

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

Program will run for few minutes. After some time it prints that terabytes of memory has been allocated but I don't see much change in System Monitor app. Why is that?

I use Linux and System Monitor app to see usages.

#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";
}

解决方案

In the modern cruel world calling new (as well as malloc() or even brk()) doesn't necessarily allocate memory. It just sends (through a chain of layers) a request to an OS and the OS assigns a virtual memory area (rounded to system memory pages). So only subsequent accessing to a given memory performs actual allocation.

Moreover modern OSes allow memory "overcommit". Sometimes (depending on OS and its settings) applications can demand totally more memory that the OS could assign even theoretically, including all its swap areas etc, all w/o any visible problem. Look at this page for example.

This is done because in real life a situation when all applications would actually use all allocated memory in the same time is quite improbable. More often, 99.99..% of time, applications use only parts of their memory and do it sequently, so an OS has a chance to serve their requests seamlessly.

To increase chances to actually cause a memory allocation error, you may access the just allocated element, but again I wouldn't call it a verbatim warranty, just "about increasing possibilities".

In the worst case when such an OS actually finds that it can't assign enough (virtual) memory because too many apps simultaneously requested access to their seamingly allocated data, OS memory manager initiates a special procedure called "OOM killer" which simply kills heuristically (= randomly :)) chosen applications.

So relying on bad_alloc is a bad idea nowadays. Sometimes you can realiably receive it (e.g. when artificially limiting your app with ulimit/setrlimit), but in general your application will run in an environment which won't guarantee anything. Just not be a memory hog and pray for the rest :)

这篇关于函数不会引发bad_alloc异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆