【问题标题】:function doesn't throw bad_alloc exception函数不会抛出 bad_alloc 异常
【发布时间】:2015-12-17 03:41:01
【问题描述】:

我正在尝试从 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";
}

【问题讨论】:

  • 与简单的内存分配相比,输出将花费 很多 的时间。如果运行 2 分钟,输出可能是 1:56,分配仍然是 4 秒。
  • 在现代残酷的世界中,调用new(以及malloc 甚至brk())并不一定会分配内存。它只是(通过层链)向操作系统发送一个请求,并且操作系统分配一个 virtual 内存区域(四舍五入到页面)。所以只有访问给定的页面会执行内存分配。此外,现代操作系统允许“过度使用”,即从操作系统可以分配的不同应用程序分配更多内存,即使使用交换也是如此。这样做是因为很少有所有应用程序同时需要所有分配的内存,并且可以依次满足它们的实际需求。
  • 在最坏的情况下,当应用程序确实访问它们的内存时,一个名为 OOM Killer 的特殊系统服务会出现并杀死应用程序(几乎是随机的:))。所以依赖bad_alloc 确实是个坏主意,它可能会提高,也可能不会,这取决于当前的操作系统设置和应用程序执行时的其他应用程序行为。
  • 为了增加实际分配虚拟页面的机会,您可以访问刚刚分配的元素,但这也不是逐字保证,只是增加了可能性

标签: c++ exception out-of-memory bad-alloc


【解决方案1】:

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

此外,现代操作系统允许内存“过度使用”。有时(取决于操作系统及其设置)应用程序可能需要操作系统甚至在理论上可以分配的更多内存,包括其所有交换区域等,所有这些都没有任何可见的问题。以at this page 为例。

这样做是因为在现实生活中,所有应用程序在同一时间实际使用所有分配的内存的情况是非常不可能的。更常见的是,99.99..% 的时间,应用程序只使用部分内存并按顺序执行,因此操作系统有机会无缝地满足其请求。

为了增加实际导致内存分配错误的机会,您可以访问刚刚分配的元素,但我不会再将其称为逐字保证,只是“关于增加可能性”。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    相关资源
    最近更新 更多