C++ std::未进入交换空间的错误分配

C++ std::未进入交换空间的错误分配,c++,heap,C++,Heap,我试图理解为什么当我似乎有足够的(虚拟的?)内存可用时,我会出现std::bad_alloc异常。 本质上,我有一个素数生成器(Eratosthenes筛(尚未分段)),其中我为一个指示符数组生成布尔值,然后为我在命令行上指定的边界下找到的素数生成整数 我有1GB的RAM(其中一些会被我的操作系统(Ubuntu10.04)占用,可能其中一些无法用作堆内存(我错了吗?)和2.8GB的交换空间(我相信在安装Ubuntu10.04时会自动设置) 如果我将上限设置为600000000,那么我要求为我的指

我试图理解为什么当我似乎有足够的(虚拟的?)内存可用时,我会出现std::bad_alloc异常。 本质上,我有一个素数生成器(Eratosthenes筛(尚未分段)),其中我为一个指示符数组生成布尔值,然后为我在命令行上指定的边界下找到的素数生成整数

我有1GB的RAM(其中一些会被我的操作系统(Ubuntu10.04)占用,可能其中一些无法用作堆内存(我错了吗?)和2.8GB的交换空间(我相信在安装Ubuntu10.04时会自动设置)

如果我将上限设置为600000000,那么我要求为我的指示符数组提供0.6GB的内存,为我的素数数组提供大约30000000*4字节的内存(稍微高估了一下,因为有26355867个素数小于500000000),以及一些变量;这意味着我需要大约.72(+可以忽略不计)GB的内存,我认为这应该由可用的交换空间来覆盖(我知道触摸这些东西会让我的程序慢得可笑)。然而,我得到了性病::坏的

有人能指出我这里遗漏了什么吗?(在粘贴上一个错误之前,最后一件将长整型改为整型的事情是seg错误(虽然我的数字远低于2^31,但我看不出溢出的地方)-仍在努力找出这个错误)

我的代码如下所示(在不影响我自己对更快算法等的研究的情况下,我会很感激这里的任何代码改进!(即,如果我犯了重大错误)

main.cpp

#include <iostream>
#include <cmath>
#include "Prime.hpp"
#include <ctime>
#include <stdio.h>
#include <cstring>

//USAGE: execute program with the nth prime you want and an upper bound for finding primes --too high may cause bad alloc
int main(int argc, const char *argv[])
{
    int a = strlen(argv[1]);
    clock_t start = clock();
    if(argc != 2)
    {
        std::cout << "USAGE: Enter a positive inputNumber <= 500000000.\n"
          << "This inputNumber is an upper bound for the primes that can be found\n";
        return -1;
    }
    const char* primeBound = argv[1];
    int inputNum = 0;
    for(int i = 0; i < strlen(argv[1]); i++)
    {
    if(primeBound[i] < 48 || primeBound[i] > 57 || primeBound[0] == 48)
    {
        std::cout << "USAGE: Enter a positive inputNumber <= 500000000.\n"
              << "This inputNumber is an upper bound for the primes that can be found\n";
        return -1;
    }
    inputNum = (int)(primeBound[i]-48) + (10 * inputNum);
    }
    if(inputNum > 600000000)//getting close to the memory limit for this machine (1GB - memory used by the OS):
                   //(each bool takes 1 byte and I'd be asking for more than 500 million of these 
                   //and I'd also asking for over 100000000 bytes to store the primes > 0.6 GB)
    {
    std::cout << "USAGE: Enter a positive inputNumber <= 500000000.\n"
          << "This inputNumber is an upper bound for the primes that can be found\n";
        return -1;
    }

    Prime p(inputNum);
    std::cout << "the largest prime less than " << inputNum << " is: " << p.getPrime(p.getNoOfPrimes()) << "\n";
    std::cout << "Number of primes: " << p.getNoOfPrimes() << "\n";
    std::cout << ((double)clock() - start) / CLOCKS_PER_SEC << "\n";
  return 0;
}
#包括
#包括
#包括“Prime.hpp”
#包括
#包括
#包括
//用法:使用所需的第n个素数和查找素数的上限执行程序——过高可能导致错误的alloc
int main(int argc,const char*argv[]
{
int a=strlen(argv[1]);
时钟启动=时钟();
如果(argc!=2)
{

std::cout程序内部可使用的内存量受到以下两个较小值的限制:1)可用虚拟内存,2)可用地址空间

如果在具有平面内存模型的平台上将程序编译为32位可执行文件,则单个进程的可寻址空间的绝对限制为4GB。在这种情况下,可用交换空间的大小完全无关。在平面内存32位程序中,即使仍然有4GB,也不能分配超过4GB的空间大量的可用交换空间。此外,这些4GB可用地址中的很大一部分将保留用于系统需要

在这样一个32位的平台上,分配大量的交换空间是有意义的,因为它可以让您同时运行多个进程。但它无法克服每个特定进程的4GB地址空间障碍

基本上,可以将其视为一个电话号码可用性问题:如果某个地区使用7位数的电话号码,那么一旦该地区可用的7位数电话号码用完,为该地区生产更多的电话就不再有任何意义——它们将不可用。通过增加交换空间,你基本上可以“生产电话”。但您已经没有可用的“电话号码”


当然,在平面内存模式的64位平台上也存在同样的问题。但是,64位平台的地址空间非常大,不再是瓶颈(你知道,“64位应该对每个人都足够了”:)

由于程序的内存使用非常容易分析,只需完全固定内存布局。不要动态分配任何内容。使用
std::bitset
获得固定大小的位向量,并将其作为全局变量

std::bitset< 600000000 > indicators; // 75 MB
std::位集<600000000>指示符;//75 MB
这不会占用磁盘空间。操作系统只会在您沿着阵列前进的过程中分配零页。它可以更好地利用每一位

当然,一半的位表示偶数,尽管只有一个偶数素数。是一对素数生成器,可以优化这些东西


顺便说一句,如果可能的话,最好避免显式地编写
new
,避免从构造函数调用函数,并重新调用
std::bad_alloc
,以避免将对象构造成无效状态。

分配筛选时

void Prime::allocateIndicatorArray(int num)
{
    try
    {
        primeIndicators = new bool[num];
    }
    catch(std::bad_alloc ba)
    {
    std::cout << "not enough memory :[";
    }
    lastStorageSize = num;
}
尝试分配
int
数组中的
lastStorageSize
元素

如果
num
约为5亿,则您所需的空间约为2GB。根据操作系统/过度使用策略,这很容易导致
分配错误,即使您实际上只需要一小部分空间

筛选完成后,将
noOfPrimes
设置为找到的素数的计数-使用该数字分配素数数组。

第一个问题是“正在运行哪些其他进程?” 2.87 GB的交换空间在所有运行 过程;它不是每一个过程。坦率地说,在现代 系统,2.8GB对我来说相当低。我不会尝试运行 最新版本的Windows或Linux,内存小于2GB,并且 4GB交换(Linux的最新版本,至少在Ubuntu中是如此) 尤其是发行版,似乎启动了很多守护进程 你可能想试试
top
,在上面排序 虚拟内存大小,只看其他进程有多少 拿着

cat/proc/meminfo
也会给你带来很多有价值的信息 关于实际使用内容的信息。(在我的系统上, 使用
bash
,再加上
Firefox
,只运行两个
xterm
,我 在8GB的系统上,只有3623776KB的可用空间 使用的内存可能是磁盘缓存之类的东西, 如果应用程序请求,系统可以缩小该范围 内存。)

第二,关于seg故障:默认情况下,Linux不会 始终报告allwa
std::bitset< 600000000 > indicators; // 75 MB
void Prime::allocateIndicatorArray(int num)
{
    try
    {
        primeIndicators = new bool[num];
    }
    catch(std::bad_alloc ba)
    {
    std::cout << "not enough memory :[";
    }
    lastStorageSize = num;
}
void Prime::allocatePrimesArray()
{
    try
    {
        primes = new int[lastStorageSize];
    }
    catch(std::bad_alloc ba)
    {
    std::cout << "not enough memory :[";
    }
}