std :: vector swap导致内存碎片?

时间:2013-06-04 14:06:22

标签: c++

我目前正在处理大约2.5GB内存的非常大的数据集。

我目前通过使用包含的类Data的向量来存储它 1)元数据 2)boost::ptr_list<MemoryBlock>

MemoryBlock类包含 1)元数据 2)std::vector<XYZ>

填充时,我将我的std::vector<xyz>保留为50,000组。如果我的矢量的空间维度变大,我将创建一个新的内存块并使用 std::vector<XYZ>(Points).swap(Points)将矢量缩小到合适的大小。

现在问题...... 似乎当我使用交换技巧来调整我的数组大小时,在清除所有数据并加载到新数据集后,我开始遇到std :: bad_alloc异常。

我可以加载的数据量大幅缩减......每次清除数据并加载到新数据集时,它将继续这样做...例如,我的初始数据集将加载100,000,000值

下次它将加载70,000,000个值

下次50,000,000个值

下次有20,000,000个值 等...

我的第一个想法是内存泄漏,但我无法识别。除了交换之外,代码中的所有内容都已经被广泛使用了很长时间而没有任何问题。

如果我不使用交换/空间维度检查,一切都会继续并正常运行。

任何想法?!?

修改

bool Check_MemBlock_Size(MemoryBlock &CurrMemblock, XYZ CheckPoint){

    // Set a minimum of 5000 points in each memory block regardless of physical size..
    if(CurrMemblock.PointsArr.size() > 5000){
        XYZ TestMin, TestMax;
        TestMin = CurrMemblock.Min;
        TestMax = CurrMemblock.Max;

        // Check what the bounding box would be if we included the check point..
        if(TestMax.x < CheckPoint.x)
            TestMax.x = CheckPoint.x;
        if(TestMax.y < CheckPoint.y)
            TestMax.y = CheckPoint.y;
        if(TestMax.z < CheckPoint.z)
            TestMax.z = CheckPoint.z;

        if(TestMin.x > CheckPoint.x)
            TestMin.x = CheckPoint.x;
        if(TestMin.y > CheckPoint.y)
            TestMin.y = CheckPoint.y;
        if(TestMin.z > CheckPoint.z)
            TestMin.z = CheckPoint.z;

        // If the new bounding box is too big, lets break it off.
        if(fabs(TestMax.x - TestMin.x) > 100 || fabs(TestMax.y - TestMin.y) > 100 || fabs(TestMax.z - TestMin.z) > 50){

            std::vector<XYZ>(CurrMemblock.PointsArr).swap(CurrMemblock.PointsArr);

            return false;

        }
    }


    return true;
}

以下是使用此代码的代码段。

                    if(Check_MemBlock_Size(*MemBlock, NewPoint) == false){

                        Data->MemoryBlocks.push_back(MemBlock);

                        try {
                            MemBlock = new MemoryBlock();
                        } catch (std::bad_alloc) {
                            printf("Not enough memory\n");
                            delete Buffer;
                            break;
                        }

                        BlockSize = 0;

                        try{
                            MemBlock->PointsArr.reserve(MaxBlockSize);
                        } catch(std::bad_alloc){
                            delete MemBlock;
                            delete Buffer;
                            printf("Not enough memory\n");
                            break;
                        }

                    }


                    // Push the point to our current memory block
                    BlockSize++;
                    MemBlock->PointsArr.push_back(NewPoint);

                    .... // More stuff going on here.. irrelevant

                    // push a new memory block if we hit the block point limit.
                    if(BlockSize >= MaxBlockSize){

                        Data->MemoryBlocks.push_back(MemBlock);

                        try {
                            MemBlock = new MemoryBlock();
                        } catch (std::bad_alloc) {
                            printf("Not enough memory\n");
                            delete Buffer;
                            break;
                        }

                        BlockSize = 0;

                        try{
                            MemBlock->PointsArr.reserve(MaxBlockSize);
                        } catch(std::bad_alloc){
                            printf("Not enough memory\n");
                            delete MemBlock;
                            delete Buffer;
                            break;
                        }

                    }

1 个答案:

答案 0 :(得分:6)

如果对Check_MemBlock_Size()进行中间调用,您可以进行更多动态分配,这种技术似乎可以保证碎片化。这是因为在分配较小的块之后释放50K分配,在内存中创建一个50K的对象孔,现在可以部分填充更多的内存,下次重建MemoryBlock时无法使用。

您可以创建一个全局向量而不是临时向量来保存此50K对象分配。然后,当您下次重建新的MemoryBlock时,而不是调整新的50K对象向量,只需交换全局对象向量。当你想缩小它时,再次换掉全局的那个。以这种方式重用50K保留内存将删除此分配可能贡献的任何碎片。

但是,如果您确定没有泄漏,程序中可能还有其他碎片来源。通常,碎片是由动态分配的大型和小型对象的混合引起的,每个对象具有不同的生命周期。有很多方法可以解决它,但处理它的一种方法是使用内存池。在这种意义上,池是具有相同大小和相同生命周期的对象的集合,在自定义分配器中组合在一起。释放此类内存将返回其池中。如果内存永远不会返回到具有delete的系统,则池将通过允许将来的分配重用先前为同一对象类型分配的内存来对抗碎片。这些池的运行时利用率达到了峰值,而碎片化的情况绝不会比这更糟糕。