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

raf*_*ges 5 c++ memory memory-management vector c++11

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

这里有一个简化版的程序.如您所见,class Foo只有一个字段:a 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

use*_*854 10

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


Mik*_*ine 3

@user1641854 的答案对于发生这种情况的原因是正确的。这个答案是关于修复它的。

有一种相对简单的方法可以解决您的问题。您可以为您的向量提供一个allocator内部直接向操作系统请求内存并在释放时直接将其释放回操作系统的内存。这通常是不可取的,因为直接从操作系统分配通常比设计良好的用户模式堆分配/释放速度慢,并且您会在页面末尾浪费一些内存。另外,如果不付出一些努力,它就不会跨平台。

话虽如此,你的案例似乎是一个合理的尝试。

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

然后在 Windows 上使用::VirtualAlloc/或在 Linux 上使用/作为底层分配/释放函数。::VirtualFreemmapmunmap