C++内存分配错误,没有使用new

C++ memory allocation errors without use of new

本文关键字:new 内存 分配 错误 C++      更新时间:2023-10-16

我的程序出现问题,引发了大量内存分配异常,我很难诊断出问题。。。我会发布代码,但我的程序很大,而且我有专有信息问题,所以我希望在不发布代码的情况下得到一些帮助。如果你打算用某种形式的SSCCE评论来回应,现在就停止阅读,为我们节省一些时间。在这种情况下,我无法发布简洁的代码——我会尽可能清楚简洁地描述问题和一些具体问题。

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

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

我知道没有代码很难提供帮助。请试着给我一些方向。我的具体问题如下:

  1. 如果我没有使用"new"和"delete",并且我的所有变量都在本地函数内部初始化,那么通过重复的函数调用是否可能出现内存泄漏/分配问题?当初始化变量时,我可以或应该做些什么来管理内存吗?包括使用"vector Instance;"声明我的变量的局部函数?

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

  3. 使用与内存有关的调整大小是否有问题?这会是我应该使用"new"和"delete"的例子吗?

  4. [与3相关]在问题函数中,我正在创建一个类变量,然后在该变量上写大约20次(我的模型的每个"迭代"一次)。当我这样做的时候,我不需要上一次迭代的数据。。。因此,我可以表面上为每次迭代创建一个新的变量实例,但我不明白这会有什么帮助(因为很明显,我可以在前34个数据切片上的一个实例上完成所有20次迭代)

任何想法都将不胜感激。我可以尝试发布一些代码,但我已经尝试过一次了,每个人似乎都被它不可编译的事实分散了注意力。我可以发布有问题的函数,但它不是自己编译的。

这是导致问题的类:

// 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;
        }
    }
}

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

如果程序不使用大量堆内存(因此它们不会耗尽堆内存),则bad_alloc很可能是由堆损坏引起的,而堆损坏通常是由在堆中使用悬空指针引起的。

您提到您的代码执行了大量的resize操作——大多数集合上的resize会使集合上的所有迭代器失效,因此,如果在resize之后重用任何迭代器,则可能会导致堆损坏,从而显示bad_alloc异常。如果使用未检查的矢量元素访问(std::vector::operator[]),并且索引超出范围,那么也可能导致堆损坏。

通常,跟踪堆损坏和内存错误的最佳方法是使用堆调试器,如valgrind

允许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.118.8,19.2)的异常或由标准异常类派生的异常来报告错误。

如果我没有使用"new"和"delete",并且我的所有变量都在本地函数内部初始化,那么通过重复的函数调用是否可能出现内存泄漏/分配问题?

不清楚。如果您引用的所有变量都是本地变量,则为否。如果您使用malloc()、calloc()和free(),则为是。

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

如果你有坏脾气就不会。如果出现"堆栈溢出"错误,是的。

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

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

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

当然。你可以跑出去。

这可能是一个我应该使用"新"和"删除"的例子吗

如果不了解更多有关数据结构的信息,这在今天是不可能的。

(在很多情况下,我都被警告不要使用这些,除非有非常有力、具体的理由这样做)?

由谁?为什么?

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

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

然后写大约20次这个变量(我的模型的每个"迭代"一次)。

有任务吗?这个类有赋值运算符吗?这是正确的吗?类本身是否使用堆内存?它在建造、销毁和分配时是否正确分配和删除?

正如您所说,由于您使用的是带有默认分配器的std::vector,所以当您使用大量std::vector::resize(...)时会出现问题,并且会在一些迭代后出现问题,我猜您会遇到堆碎片问题。