不使用new的C ++内存分配错误

时间:2013-07-30 22:10:12

标签: c++ bad-alloc

我遇到的问题是我的程序抛出了大量的内存分配异常而且我很难诊断问题...我会发布代码,但是我的程序非常大而且我有专有的信息问题,所以我希望在不发布代码的情况下得到一些帮助。如果您打算使用某种形式的SSCCE评论做出回应,请立即停止阅读并保存我们两个人的时间。这是一个我无法发布简洁代码的情况 - 我会尽量使用我的问题描述和一些具体问题尽可能简洁明了。

计划背景 - 我的程序基本上是一个数据处理程序。它需要一堆数据表作为输入,对它们执行计算,并根据计算结果吐出新的数据表。我的所有数据结构都是用户定义的类(由int,double和string类型组成,带有用于数组的向量容器)。在所有情况下,我都会在不使用new和delete的情况下启动类变量的实例。

问题描述 - 我的程序在没有警告的情况下编译,并且在较小的数据集上运行良好。但是,一旦我增加了数据集(从20x80数组到400x80),我就开始抛出bad_alloc异常(一旦我处理了前35个条目左右)。大型数据集在我的18个模块中的17个中运行良好 - 我已经隔离了一个发生错误的函数。此函数所需的计算将导致创建大约30,000行数据,而我的代码中的其他函数生成800,000多行而不会发生意外。
     这个模块中唯一真正的唯一属性是我正在大量调整大小(每个函数调用大约100次),并且该函数在调整大小操作期间使用递归循环(该函数在建筑物一个租户之外分配平方英尺)一段时间,然后在模拟每个租户租约大小和持续时间之后更新要分配的剩余脚,直到分配了所有平方英尺)。此外,错误每次都发生在几乎相同的地方(但不是完全相同的位置,因为我有一个随机数生成器,它会对结果产生一些变化)。让我感到困惑的是,对这个函数的第一次~34次调用工作正常,~35调用不需要比之前的34更多的内存,但是我在第35次调用时遇到了这些bad_alloc异常......

我知道没有代码就很难提供帮助。请尽量给我一些指导。我的具体问题如下:

  1. 如果我没有使用“new”和“delete”,并且我的所有变量都在本地函数的INSIDE中初始化,是否可能通过重复的函数调用产生内存泄漏/分配问题?当使用“向量实例”初始化包含局部函数的变量时,我可以或应该做些什么来管理内存声明我的变量?

  2. 如果我通过堆栈执行整个程序,是否有可能在堆栈内存上运行不足?是否有可能我需要在堆上加载一些大的查找表(映射等),然后在速度很重要的迭代中使用堆栈?

  3. 使用与内存相关的调整大小是否有问题?这可能是我应该使用“新”和“删除”的实例(在许多情况下我被警告不要使用那些,除非有非常强烈的,具体的理由这样做)?

  4. [与3相关]在问题函数中,我正在创建一个类变量,然后将该变量写入大约20次(对于我的模型的每次“迭代”一次)。当我这样做时,我不需要上一次迭代的数据...所以我可以表面上为每次迭代创建一个新的变量实例,但我不明白这将如何有所帮助(因为我能够清楚)在第一个~34个数据切片上的一个实例上进行所有20次迭代)

  5. 任何想法都将不胜感激。我可以尝试发布一些代码,但我已经尝试了一次,每个人似乎都因为它不可编辑而分心。我可以发布有问题的函数,但它本身不能编译。

    以下是导致问题的类:

    // Class definition
    class SpaceBlockRentRoll
    {
    public:
        double RBA;
        string Tenant;
        int TenantNumber;
        double DefaultTenantPD;
        int StartMonth;
        int EndMonth;
        int RentPSF;
        vector<double> OccupancyVector;
        vector<double> RentVector;
    };
    
    // Class variable declaration (occuring inside function)
    vector<SpaceBlockRentRoll> RentRoll;
    

    此外,这里是发生递归的函数的片段

    for (int s=1; s<=NumofPaths; ++s) {
        TenantCounter = 0;
        RemainingTenantSF = t1SF;
        if (RemainingTenantSF > 0) {
            while (RemainingTenantSF > 0) {
                TenantCounter = TenantCounter + 1;
    
                // Resize relevant RentRoll vectors
                ResizeRentRoll(TenantCounter, NumofPaths, NumofPeriods, RentRoll);
    
                // Assign values for current tenant
                RentRoll[TenantCounter] = AssignRentRollValues(MP, RR)  
                // Update the square feet yet to be allocated
                RemainingTenantSF = RemainingTenantSF - RentRoll[TenantCounter].RBA;
            }
        }
    }
    

4 个答案:

答案 0 :(得分:6)

bad_alloc来自某种堆的问题,并且可以由任何间接分配或释放堆内存的代码抛出,其中包括所有标准库集合(std::vectorstd::map等)以及std::string

如果您的程序不使用大量堆内存(因此它们没有用完堆),bad_alloc可能是由堆损坏引起的,这通常是由于使用悬空指针进入堆中引起的

你提到你的代码执行了很多resize操作 - resize对大多数集合都会使集合上的所有迭代器无效,所以如果你在resize之后重用任何迭代器,这可能导致堆损坏,表现出bad_alloc个异常。如果使用未经检查的向量元素访问(std::vector::operator[]),并且索引超出范围,则也可能导致堆损坏。

一般来说,追踪堆损坏和内存错误的最佳方法是使用堆调试器,例如valgrind

答案 1 :(得分:3)

std::vectorstd::string等类允许抛出bad_alloc或其他异常。毕竟,他们必须使用来自某个地方的一些内存,而任何计算机都只有很多内存可供使用。

标准17.6.5.12/4:

  

C ++标准库中定义的析构函数操作不应抛出异常。 C ++标准库中的每个析构函数都应该表现得好像具有非抛出异常规范。除非另有说明,否则C ++标准库中定义的没有异常 - 规范的任何其他函数都可能抛出实现定义的异常。 [脚注1]实现可以通过添加显式的异常规范来加强这种隐式异常规范

     

脚注1:特别是,他们可以通过抛出类型bad_alloc的异常或从bad_alloc(18.6.2.1)派生的类来报告分配存储的失败。库实现应该通过抛出标准异常类的异常或派生出来来报告错误(18.6.2.1,18.8,19.2)。

答案 2 :(得分:2)

  

如果我没有使用“new”和“delete”,并且所有变量都在本地函数的INSIDE中初始化,是否可能通过重复的函数调用来解决内存泄漏/分配问题?

不清楚。如果您引用的所有变量都是本地变量,则不是。如果您正在使用malloc(),calloc()和free(),那么。

  

如果我通过堆栈执行整个程序,是否有可能在堆栈内存上运行不足?

如果你得到bad_alloc就没有了。如果您遇到“堆栈溢出”错误,是的。

  

我是否有可能需要在堆上加载一些大的查找表(映射等),然后在速度很重要的迭代中使用堆栈?

嗯,很难相信在递归方法的每个堆栈帧中都需要查找表的本地副本。

  

使用与内存相关的调整大小是否有问题?

当然。你可以用完。

  

这可能是我应该使用“new”和“delete”

的实例

在不了解您的数据结构的情况下,今天不可能。

  

(在许多情况下我被警告不要使用那些,除非有非常强烈的,特定的理由这样做)?

由谁?为什么呢?

  

在问题函数中,我正在创建一个类变量

您正在堆栈上创建类的实例。我认为。请澄清。

  

然后将该变量写入约20次(对于我的模型的每次“迭代”一次)。

有了作业吗?该类是否有赋值运算符?这是对的吗?类本身是否使用堆内存?是否在构造,销毁和分配时正确分配和删除了?

答案 3 :(得分:2)

正如你所说,你正在使用std::vector和默认分配器,当你使用大量std::vector::resize(...)并且在一些迭代之后发生问题时会出现问题,我猜你会遇到堆碎片问题问题