在用户定义的类中清空std :: vector时未释放内存

时间:2016-07-07 12:40:10

标签: c++ c++11 memory memory-management vector

std::vector是一个类的字段时,我们遇到了一些内存问题。我们在这个向量中填充了大量数据,这些数据需要在程序的某个点上发布。但是,即使向量容量为零,内存也不会被释放或完全释放。

这里有一个我们程序的简化版本。如您所见,课程Foo只有一个字段:std::vector<int>。如果我们创建一个std::vector<Foo>并用Foo个对象填充它,当我们清空每个对象中的向量时,内存不会完全释放。

我们使用活动监视器测量了内存使用情况,您可以在每个日志行旁边看到每个阶段使用的字节数。此外,我们添加了另一个版本,我们不使用类Foo对象,在这种情况下,内存完美释放。

#include <iostream>
#include <vector>

class Foo {

public:
    std::vector<int> container;
};

int main() {
    int n1 = 1000;
    int n2 = 100000;
    {
        std::vector<Foo> foos;

        std::cerr << "starting" << std::endl; // 160 KiB
        std::cin.get();

        for (int i = 0; i < n1; i++){
            Foo foo;
            foo.container.assign(n2, 666);
            foos.push_back(foo);
        }

        std::cerr << "foos filled" << std::endl; // 382.1 MiB
        std::cin.get();

        for (unsigned int i = 0; i < foos.size(); i++){
            std::vector<int>().swap(foos[i].container);
        }

        std::cerr << "foos emptied" << std::endl; // 195.7 MiB
        std::cin.get();
    }
    std::cerr << "foos destroyed?" << std::endl; // 296 KiB
    std::cin.get();

    {
        std::vector<std::vector<int> > foos;

        std::cerr << "starting" << std::endl; // 296 KiB
        std::cin.get();

        {
            std::vector<int> aux;
            aux.assign(n2, 666);
            foos.assign(n1, aux);
        }

        std::cerr << "foos filled" << std::endl; // 382.1 MiB
        std::cin.get();

        for (unsigned int i = 0; i < foos.size(); ++i) {
            std::vector<int>().swap(foos[i]);
        }

        std::cerr << "foos emptied" << std::endl; // 708 KiB
        std::cin.get();
    }

    std::cerr << "foos destroyed?" << std::endl; // 708 KiB
    std::cin.get();


    return 0;
}

如果有帮助,我们在Ubuntu 14.04 64位下使用g ++ 4.8.4。具体的内存占用率取决于我们是使用C ++ 11还是C ++ 98,但两种情况都会出现相同的现象。

关于发生了什么以及如何恢复记忆的任何想法,如果需要的话,强行要求?

编辑:请注意,当我们销毁Foo类的所有对象时,确实会返回内存,但在我们的实际问题中,我们仍然需要Foo的其他内容 - 模拟类。

2 个答案:

答案 0 :(得分:10)

内存从运行时C ++ / C库发布到用户空间内存分配器。通常,它并不意味着用户空间分配器会将此内存返回给操作系统。用户空间分配器按块从内核分配内存。通过new / malloc对您的请求进一步细化。当您释放/删除此切片块时,它们将返回到用户空间分配器,而不是内核。并且当用户空间分配器将能够将分配的内存块返回到内核时,仅由用户空间分配器知道。

答案 1 :(得分:3)

@ user1641854的回答是正确的,为什么会发生这种情况。这个答案是关于修复它。

有一个相对简单的方法来解决您的问题。你可以给你的向量allocator,它在内部直接向操作系统询问内存,并在释放时将其直接释放回操作系统。这通常是不合需要的,因为直接来自OS分配通常比设计良好的用户模式堆更慢地分配/释放,并且您将在页面末尾浪费一些内存。此外,如果不付出一些努力,它就不会是跨平台的。

说过你的案子似乎是一个合理的尝试。

请参阅here了解如何定义自己的分配器。

然后在Windows上使用::VirtualAlloc / ::VirtualFree或在linux上使用mmap / munmap获取基础分配/免费功能。