c++ - 为高度迭代的 c++ 程序争吵内存

标签 c++ memory-management for-loop

tl:dr 我需要一种方法来更好地管理 C++ 中的内存,同时保留大型数据集。

我目前正在创建一个程序来输出我以后项目需要的数据库,并且我正在努力解决内存控制问题。我将程序编写到功能级别,可以小规模输出我需要的数据集,但要将大小增加到我需要的位置并保持现实,我需要增加迭代次数。问题是,当我这样做时,我的计算机 (4gb) 内存不足,它必须开始页面归档,这会大大减慢处理速度。

基本大纲是我正在创建商店,然后为该商店创建一年的交易数据。创建商店时,会生成一个数字列表,代表交易的每日销售目标,然后随机生成交易,直到达到该数字。这种方法给出了一些我非常满意的很好的有机结果。不幸的是,所有这些交易都必须存储在内存中,直到它们被输出到我的文件中。

创建交易时,它们会临时存储在一个 vector 中,我在将 vector 的拷贝存储到我的永久存储位置后执行 .clear() 。

我已经开始尝试移动到 unique_ptr 作为我的临时存储,但我不确定它们是否在从生成我的数据的函数返回时被正确删除。

代码是这样的(我删掉了一些与手头问题无关的多余代码)

void store::populateTransactions() {
    vector<transaction> tempVec;
    int iterate=0, month=0;
    double dayTotal=0;
    double dayCost=0;
    int day=0;
for(int i=0; i<365; i++) {
    if(i==dsf[month]) {
        month++;
        day=0;
    }
    while(dayTotal<dailySalesTargets[i]) {
        tempVec.push_back(transaction(2013, month+1, day+1, 1.25, 1.1));
        dayTotal+=tempVec[iterate].returnTotal();
        dayCost+=tempVec[iterate].returnCost();
        iterate++;
    }
        day++;

        dailyTransactions.push_back(tempVec);
        dailyCost.push_back(dayCost);
        dailySales.push_back(dayTotal);
        tempVec.clear();
        dayTotal = 0;
        dayCost = 0;
        iterate = 0;
    }
}

transaction::transaction(int year, int month, int day, double avg, double dev) {
    rng random;
    transTime = &testing;
    testing = random.newTime(year, month, day);
    itemCount = round(random.newNum('l', avg, dev,0));
    if(itemCount <= 0) {
        itemCount = 1;
    }

    for(int i=0; i<itemCount; i++) {
        int select = random.newNum(0,libs::products.products.size());
        items.push_back(libs::products.products[select]);
        transTotal += items[i].returnPrice();
        transCost += items[i].returnCost();
    }
}

最佳答案

您遇到内存问题的原因是,当您向 vector 添加元素时,它最终必须调整其内部缓冲区的大小。这需要分配一个新的内存块,将现有数据复制到新成员,然后删除旧缓冲区。

由于您事先知道 vector 将容纳的元素数量,因此您可以调用 vector 的 reserve() 成员函数来提前分配内存。这将消除您现在无疑会遇到的不断调整大小的问题。

例如,在 transaction 的构造函数中,您可以在将数据添加到 vector 的循环之前执行以下操作。

items.reserve(itemCount);

store::populateTransactions() 中,您应该计算 vector 将包含的元素总数并调用 tempVec.reserve(),方法与上述相同。还要记住,如果您使用局部变量来填充 vector ,您最终将需要复制它。这将导致相同的问题,因为目标 vector 需要在复制内容之前分配内存(除非您使用 C++11 中可用的移动语义)。如果数据需要返回给调用函数(而不是作为 store 的成员变量),您应该通过引用将其作为参数。

void store::populateTransactions(vector<transaction>& tempVec)
{
    //....
}

如果提前确定元素数量不切实际,您应该考虑使用 std::deque反而。来自 cppreference.com

As opposed to std::vector, the elements of a deque are not stored contiguously: typical implementations use a sequence of individually allocated fixed-size arrays.

The storage of a deque is automatically expanded and contracted as needed. Expansion of a deque is cheaper than the expansion of a std::vector because it does not involve copying of the existing elements to a new memory location.

关于 Rafael Baptista 的评论关于调整大小操作如何分配内存,以下示例应该让您更好地了解它发生了什么。列出的内存量是调整大小期间所需的量

#include <iostream>
#include <vector>

int main ()
{
    std::vector<int>    data;

    for(int i = 0; i < 10000001; i++)
    {
        size_t oldCap = data.capacity();
        data.push_back(1);
        size_t newCap = data.capacity();
        if(oldCap != newCap)
        {
            std::cout
                << "resized capacity from "
                << oldCap
                << " to "
                << newCap
                << " requiring " << (oldCap + newCap) * sizeof(int)
                << " total bytes of memory"
                << std::endl;
        }
    }
    return 0;
}

当使用 VC++10 编译时,将 1,000,001 个元素添加到 vector 时会生成以下结果。这些结果特定于 VC++10,并且可能因 std::vector 的实现而异。

resized capacity from 0 to 1 requiring 4 total bytes of memory
resized capacity from 1 to 2 requiring 12 total bytes of memory
resized capacity from 2 to 3 requiring 20 total bytes of memory
resized capacity from 3 to 4 requiring 28 total bytes of memory
resized capacity from 4 to 6 requiring 40 total bytes of memory
resized capacity from 6 to 9 requiring 60 total bytes of memory
resized capacity from 9 to 13 requiring 88 total bytes of memory
resized capacity from 13 to 19 requiring 128 total bytes of memory

...snip...

resized capacity from 2362204 to 3543306 requiring 23622040 total bytes of memory
resized capacity from 3543306 to 5314959 requiring 35433060 total bytes of memory
resized capacity from 5314959 to 7972438 requiring 53149588 total bytes of memory
resized capacity from 7972438 to 11958657 requiring 79724380 total bytes of memory

关于c++ - 为高度迭代的 c++ 程序争吵内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16876022/

相关文章:

c++ - 如何获取字符串的一部分

c++ - 在 UNIX 中通过 recv/send 交换数据时如何正确使用缓冲区?

c++ - 通过动态分配为大约 10000 个变量存储 bool 信息的内存有效方法

ios - for循环疯狂

java - 为什么在这个 for 循环之后有一个分号?

c++ - 如何为 MinGW 项目设置 OpenCV?

c++ - 参数化自定义CMake工具链

memory-management - vkCmdCopyImage 是否自动转换平铺属性?

c++ - 问题 : String writes over another string

Javascript 欧拉斐波那契 for 循环