在用户定义的类中清空std :: vector时未释放内存 [英] Memory not released when emptying std::vector inside a user-defined class

查看:384
本文介绍了在用户定义的类中清空std :: vector时未释放内存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

std::vector是一个类的字段时,我们遇到一些内存问题.我们用大量数据填充该向量,这些数据在程序的特定点需要释放.但是,即使向量容量为零,内存也不会释放或完全释放.

We are having some memory issues when std::vector is a field of a class. We fill this vector with a lot of data which, at a certain point of the program needs to be released. However, even though the vector capacity is zero, the memory is not released or completely released.

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

Here you have a simplified version of our program. As you can see, class Foo has only one field: a std::vector<int>. If we create a std::vector<Foo> and fill it with Foo objects, when we empty the vector inside each object, the memory is not completely released.

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

We have measured the memory usage using the activity monitor and you can see, next to each log line, the amount of Bytes used in each stage. Moreover, we have added another version where we don't use class Foo objects and, in that case, memory is released perfectly.

#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,但是在两种情况下都会出现相同的现象.

If it helps, we're using g++ 4.8.4 under Ubuntu 14.04 64-bit. The specific memory occupancy varies depending on whether we use C++11 or C++98, but the same phenomenon occurs in both cases.

有关发生的事情以及如何恢复该内存的任何想法(如果需要的话)?

Any ideas as to what's happening and how to recover that memory, forcibly if need be?

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

Note that memory is mostly returned indeed when we destroy all objects of the Foo class, but in our real-world problem we still need the rest of the contents of the Foo-analogue class.

推荐答案

@ user1641854的答案正确,说明了为什么会这样.这个答案是关于解决它的.

@user1641854's answer is correct to why this happens. This answer is about fixing it.

有一种相对的简单方法可以解决您的问题.您可以为向量提供一个allocator,该向量在内部直接要求操作系统提供内存,并在释放后直接将其释放回操作系统.这通常是不可取的,因为直接进行OS分配通常比设计良好的用户模式堆慢于分配/释放,并且您将在页面末尾浪费一些内存.而且,无需付出任何努力,它就不会跨平台.

There's a relatively easy way to fix your issue. You can give your vector an allocator which internally directly asks the operating system for memory and directly free's it back to the operating system when free'd. This is generally undesirable as direct from OS allocation is generally slower to allocate/free than a well designed usermode heap and you'll waste some memory at the end of pages. Also, without some effort, it would not be cross platform.

话虽如此,但您的案子似乎值得尝试.

Having said that your case seems one where this would be a reasonable thing to attempt.

有关如何定义自己的分配器的信息,请参见此处.

See here for how to define your own allocator.

然后在Windows上使用::VirtualAlloc/::VirtualFree或在Linux上使用mmap/munmap进行基础分配/释放功能.

Then use ::VirtualAlloc/::VirtualFree on windows or mmap/munmap on linux for the underlying allocation/free functions.

这篇关于在用户定义的类中清空std :: vector时未释放内存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆