8

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

我目前正在使用包含 1) 元数据 2) 的类 Data 向量来存储它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;
                        }

                    }
4

1 回答 1

6

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

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

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

于 2013-06-04T14:48:38.440 回答