C++如何停止堆中的过度分配?

zf9nrax1  于 2023-03-05  发布在  其他
关注(0)|答案(1)|浏览(121)

下面的代码:

#include <iostream>

int main()
{
    try {
        while (true)
            int* ptr = new int[10000000L];
    } catch (const std::bad_alloc& e) {
        std::cout << e.what();
        return EXIT_FAILURE;

    }
    return EXIT_SUCCESS;
}

主要的问题是std::bad_alloc异常从来没有被捕捉到,程序继续无休止地运行,没有任何错误。当然,我所有的8GB RAM被填充到95%,然后它开始使用正在使用的交换内存。因此,关于内存不足的错误不会弹出。
我使用的是常见的Windows 10操作系统。
如何修复该程序禁用使用交换内存?

elcex8rz

elcex8rz1#

首先,现代计算机使用虚拟内存,在虚拟内存系统中,内存空间中地址的指针值具有到页面的偏移量和页面索引(通常页面大小为4k,因此页面偏移量为12位)。
页在物理内存中的物理位置可能不存在,或者可能存在于完全不同的偏移量处。有一个表将页码Map到数据实际所在的位置。此表可以包括物理页偏移量,或者一个陷阱,如果尝试访问该页,该陷阱会导致代码在操作系统中执行。
因此,虽然您只有8 GB的物理内存,但这并不限制进程可以寻址的内存量。
这也是为什么不同的过程不能触及彼此的记忆;它们存在于不同的地址空间中。2同一个进程中的同一个指针值并不指向同一个页面,因为它们有不同的页表。3(在windows中,进程共享一个内核地址空间;但在内核模式之外,无论如何都不能访问这些页面,安全的OS API也不允许将用户模式值注入任何内核模式指针)
第二,你只是要求保留地址空间,一台64位计算机最多可以有2^64个内存地址(每个8位),或超过10^19。您一次分配10^7。这不会在10^12次迭代中耗尽64位地址空间(10000亿)。如果你每秒可以分配10^7次,这应该需要一天左右。
现在,并不是所有的64位系统都有完整的64位内存空间。所以它可能会更早发生。
许多操作系统允许你请求内存空间,如果你从来没有接触过,实际上不会给你分配任何物理内存,甚至磁盘上的任何空间。
第三,在C中,如果你分配了内存,却失去了所有指向它的指针,这就相当于 * 从不分配内存 *。C标准允许编译器检测noop分配,但不进行分配。
简而言之,如果你想知道你有多少内存,找一个OS API告诉你。
如果你真的想保留物理内存,这通常不可能通过用户模式代码实现,你必须拥有特殊的特权,比如成为驱动程序或者windows操作系统本身的一部分,而且驱动程序必须经过硬件制造商的签名。
有一些方法可以请求内存不被交换到磁盘,但这些方法只是请求,例如,查找Virtual Memory Functions in the windows API. VirtualLock,在999/1000的情况下使用这个方法是一个非常糟糕的主意。

相关问题