如果我只给它一个指向我对象的指针,std :: vector占用了什么内存?

时间:2016-01-22 13:12:41

标签: c++ linux memory vector stl

有一些我不理解的东西,我非常感谢一些澄清。我知道有很多关于std :: containers和内存没有被释放,但我仍然不明白一个特定的事实。

下面是一个最小程序,它代表了我在生产系统中遇到的问题。在注释中,在等待Ubuntu上的std :: cin时,从/ proc / PROC_NUM / status读取内存消耗。问题也在评论中。

#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <vector>

class MyObject
{
public:
    MyObject(int r=1000)
    : array(new float[r])
    {
        for (int i = 0; i<r;i++)
        {
            array[i] = random();
        }
    }

    ~MyObject()
    {
        delete[] array;
    }

public:
    float* array;
};


int main(int argc,char*argv[])
{
    char a;
    const int count=100;

    std::cout<<"Start after input"<<std::endl;
    std::cin >> a;
    // VmSize:     12704 kB
    {
        std::vector<MyObject*> vec;
        for(int i=0; i<count; i++)
        {
            vec.push_back(new MyObject);
        }

        std::cout<<"Release after input"<<std::endl;
        std::cin >> a;
        // VmSize:     13100 kB, alright, MyObjects fill around 400kB (what I expected)

        for (int i=0; i<count; i++)
        {
            delete vec[i];
            vec[i]=NULL;
        }

        std::cout<<"Run out of scope of vector after input"<<std::endl;
        std::cin >> a;
        // VmSize:     13096 kB, Why are the 400k not freed yet?
    }

    std::cout<<"Shutdown after input"<<std::endl;
    std::cin >> a;
    // VmSize:     12704 kB, Why are now around 400k freed? The only thing that is freed here is the vector of pointers.

    return 0;
}

如果我改为使用MyObjects数组,删除后会立即释放内存:

#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <vector>

class MyObject
{
public:
    MyObject(int r=1000)
    : array(new float[r])
    {
        for (int i = 0; i<r;i++)
        {
            array[i] = random();
        }
    }

    ~MyObject()
    {
        delete[] array;
    }

public:
    float* array;
};


int main(int argc,char*argv[])
{
    char a;
    const int count=100;

    std::cout<<"Start after input"<<std::endl;
    std::cin >> a;
    // VmSize:     12700 kB
    {
        MyObject* vec(new MyObject[count]);

        std::cout<<"Release after input"<<std::endl;
        std::cin >> a;
        // VmSize:     13096 kB, alright, around 400k again
        delete[] vec;

        std::cout<<"Run out of scope of vector after input"<<std::endl;
        std::cin >> a;
        // VmSize:     12700 kB, 400k freed again, perfect.
    }

    std::cout<<"Shutdown after input"<<std::endl;
    std::cin >> a;
    // VmSize:     12700 kB, nothing changed, as expected
    return 0;
}

我读到的答案告诉我不能相信操作系统的内存号码(目前我在Linux上使用了/ prop / PROC_NO / status的输出)。我可以使用什么来监控内存消耗?我在XCode Instruments的Mac上试过同样的东西,我甚至没有那个问题。第一种情况下的含义内存消耗等于第二种情况。

在Ubuntu上,我尝试了不同版本的gcc和clang,它们都表现出相同的行为。

在我的高效系统中,有一个std :: map而不是std :: vector,但问题是一样的。

3 个答案:

答案 0 :(得分:3)

VMSize与范围语言中范围的输入和离开几乎没有关系(存在那些没有范围的编程环境?)。

VMSize反映了操作系统实际必须使用哪个内存来满足程序的内存要求。例如,如果使用mallocnew[]或匿名mmap分配大块内存,则地址空间仅保留,但不会被占用,因此不会显示在VMSize中。

此外,大多数运行时库分配大量存储器中的内存,而对象分配则是来自这些大型存储器的片段;在释放对象之后,只有块中的空格被标记为空闲,并且可以在下一次分配时被回收。如果释放从中分配的所有对象并且没有其他对象驻留在其中,则释放如此大量内存的典型提示。所以你的std :: vector和你手动分配的对象很可能是从同一个Hunk分配的,并且std :: vector实例可以防止它被返回到系统。 但这只是猜想!详细信息取决于所使用的C ++运行时库。

答案 1 :(得分:0)

在第一个示例中,您在范围内的堆栈上创建了向量。您可能知道C ++有RAII http://en.cppreference.com/w/cpp/language/raii来自动进行资源管理,当您离开范围内存保留给vector时,将被释放。这就是为什么你在你的例子结尾再次看到VmSize:12704的原因!

如果您不在堆栈上创建向量,则第一个示例的行为将与预期的一样。

#include <iostream>
#include <stdlib.h>
#include <fstream>
#include <vector>
#include "stdlib.h"
#include "stdio.h"
#include "string.h"


int parseLine(char* line){
    int i = strlen(line);
    while (*line < '0' || *line > '9') line++;
    line[i-3] = '\0';
    i = atoi(line);
    return i;
}


int getValue(){ //Note: this value is in KB!
    FILE* file = fopen("/proc/self/status", "r");
    int result = -1;
    char line[128];


    while (fgets(line, 128, file) != NULL){
        if (strncmp(line, "VmSize:", 7) == 0){
            result = parseLine(line);
            break;
        }
    }
    fclose(file);
    return result;
}

class MyObject
{
public:
    MyObject(int r=1000)
    : array(new float[r])
    {
        for (int i = 0; i<r;i++)
        {
            array[i] = random();
        }
    }

    ~MyObject()
    {
        delete[] array;
    }

public:
    float* array;
};


int main(int argc,char*argv[])
{

    const int count=100;
    // VmSize:     12704 kB
    std::cout << "VmSize: " << getValue() << std::endl;
    {
        std::vector<MyObject*> *vec = new std::vector<MyObject*>();
        for(int i=0; i<count; i++)
        {
            vec->push_back(new MyObject);
        }

        // VmSize:     13100 kB, alright, MyObjects fill around 400kB (what I expected)
        std::cout << "VmSize: " << getValue() << std::endl;

        for (int i=0; i<count; i++)
        {
            delete (*vec)[i];
            (*vec)[i]=NULL;
        }

//Now we deallocating memory! In case of stack it will be done automatically when we left the scope.
        delete vec;
        std::cout << "VmSize: " << getValue() << std::endl;
        // VmSize:     13096 kB, Why are the 400k not freed yet?
    }

    std::cout << "VmSize: " << getValue() << std::endl;
    // VmSize:     12704 kB, Why are now around 400k freed? The only thing that is freed here is the vector of pointers.

    return 0;
}

答案 2 :(得分:0)

您的期望是正确的!这是因为GCC的STL分配策略。 GCC使用启发式方法。例如,您可能需要重新插入对象。所以在整个向量消失之前,你对MyObject的析构函数的调用是内部的null语句!可在此处找到完整说明:https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html

根据上述链接的说明:要关闭STL优化,请设置GLIBCXX_FORCE_NEW。 我试过这样:

export GLIBCXX_FORCE_NEW=1
./a.out

现在内存立即被释放!