vector <string>和map <string,int>在解除分配时可能出现故障?想知道内存使用细节</string,int> </string>

时间:2012-12-30 04:05:35

标签: c++ memory-leaks stl vector

我正在用c ++编写处理大量包含毫秒节点信息的流数据。我使用vector来存储每个节点的名称并映射索引。

现在的问题是,向量占用的内存比预期多得多,而且它们的破坏无法解释。

假设somefile包含100万行,每行超过50个字符。两次读取它们,然后检查进程的内存使用情况和向量的估计内存使用情况。它们的差异在60 MB。这只是我所遇到的更大问题的一个小预测,它可能在GB范围内有所不同。

我在Windows7 SP1 Ultimate 64bit上使用VS2010 SP1,使用x86设置编译程序。

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <Windows.h>
#include <Psapi.h>
using namespace std;

//#define COUNT 500000
int COUNT = 0;

vector<string> namesVector;
map<string,int> namesMap;
void ProcessStatistics()
{   
    PROCESS_MEMORY_COUNTERS memCounter;
    GetProcessMemoryInfo(GetCurrentProcess(),&memCounter,sizeof(memCounter));
    cout<<"Mem Usage by Process: "<<memCounter.WorkingSetSize * 1.0e-6f<<" MB."<<endl;
}
void VectorMemUsage()
{   
    COUNT = namesVector.size();
    int overhead = StringOverhead();
    double mem = 0;
    mem += sizeof(vector<string>);
    mem += overhead*COUNT;
    for(int i=0; i<COUNT; i++)
    {
        mem += namesVector[i].capacity();
    }
    cout<<"Calculated String Vector Usage: "<<mem * 1.0e-6f<<" MB of "<<COUNT<<" strings."<<endl;
}
int StringOverhead()
{
    int overhead = sizeof(string);
    cout<<"String overhead: "<<overhead<<" Bytes."<<endl;   
    return overhead;
}

void main(){
    const std::string infile = "somefile";
    ifstream infstream(infile);
    string s;   
    while(getline(infstream,s) != NULL)
    {
        namesVector.push_back(s);
        //namesMap.insert(pair<string,int>(s,namesVector.size()));
    }
    infstream.clear();
    infstream.seekg(0,ios::beg);    
    while(getline(infstream,s) != NULL)
    {
        namesVector.push_back(s);
        //namesMap.insert(pair<string,int>(s,namesVector.size()));
    }
    //Check process and vector memory usage:
    ProcessStatistics();
    VectorMemUsage();
    System("pause");

    //Release the vector.
    cout<<"Now releasing the memory..."<<endl;        
    //vector<string>(namesVector).swap(namesVector);
    //vector<string>().swap(namesVector); //Deallocate Vector
//map<string,int>().swap(namesMap);   //Deallocate Map
    cout<<"Capacity of vector "<<namesVector.capacity()<<endl;
    ProcessStatistics();
 }

程序输出的x86版本:

Mem Usage by Process: 336.523 MB.
String overhead: 28 Bytes.
Calculated String Vector Usage: 301.599 MB of 3385108 strings.
Press any key to continue . . .
Now releasing the memory...
Mem Usage by Process: 7.64314 MB.

当我在向量上调用namesVector.shrink_to_fit()或vector(namesVector).swap(namesVector)成语时,向量容量确实减少了,但内存使用率很高,任何人都有想法解决这个问题?交换技巧应该是指针交换吗?为什么它会涉及内存复制和所有并导致这个?

Mem Usage by Process: 336.536 MB.
String overhead: 28 Bytes.
Calculated String Usage: 301.599 MB of 3385108 strings.
Vector Capacity is 3543306.
Calculated String Vector Usage: 315.693 MB of 3385108 strings.
Now releasing the memory...
Capacity of vector 3385108
Mem Usage by Process: 434.5 MB.

当我为字符串索引添加地图时,发生了意外行为。当我同时调用vector()。swap(namesVector)和map()。swap(namesMap)时,结果是这样的,这很好,因为内存已经释放。

Mem Usage by Process: 534.778 MB.
String overhead: 28 Bytes.
Calculated String Usage: 301.599 MB of 3385108 strings.
Vector Capacity is 3543306.
Calculated String Vector Usage: 315.693 MB of 3385108 strings.
Press any key to continue . . .
Now releasing the memory...
Capacity of vector 0
Mem Usage by Process: 8.2903 MB.

但是当我只调用vector()。swap(namesVector)时,内存被部分释放。部分我的意思是它释放的数字少于上面的结果,大约336 MB。

Mem Usage by Process: **534.77** MB.
String overhead: 28 Bytes.
Calculated String Usage: 301.599 MB of 3385108 strings.
Vector Capacity is 3543306.
Calculated String Vector Usage: 315.693 MB of 3385108 strings.
Press any key to continue . . .
Now releasing the memory...
Capacity of vector 0
Mem Usage by Process: **440.459** MB.

或map()。swap(namesMap),内存接近完全没有释放。

Mem Usage by Process: **534.774** MB.
String overhead: 28 Bytes.
Calculated String Usage: 301.599 MB of 3385108 strings.
Vector Capacity is 3543306.
Calculated String Vector Usage: 315.693 MB of 3385108 strings.
Press any key to continue . . .
Now releasing the memory...
Capacity of vector 3543306
Mem Usage by Process: **535.441** MB.

我无法解释发生了什么。任何人都知道这里发生了什么?

感谢您的帮助。

最佳。

1 个答案:

答案 0 :(得分:2)

内存泄漏标记在这里不合适,永远不会有任何泄露的内存 - 所有内存都可以访问并由仍在范围内的对象拥有。内存泄漏意味着丢失的内存永远无法释放,因为您没有引用它。

VectorMemUsage中你应该使用overhead*namesVector.capacity()或者你只计算填充的向量元素,而不是已分配但未初始化的内存。为什么该函数仍然使用全局变量?最好把它写成:

void VectorMemUsage()
{   
    int overhead = StringOverhead();
    double mem = 0;
    mem += sizeof(vector<string>);
    mem += overhead*namesVector.capacity();
    for(int i=0; i < namesVector.size(); i++)
    {
        mem += namesVector[i].capacity();
    }
    cout<<"Calculated String Vector Usage: "<<mem * 1.0e-6f<<" MB of " << namesVector.size() <<" strings."<<endl;
}

如果你想避免向量中未使用的容量,你需要提前知道它将具有多少元素(即输入文件中有多少行),并使用reserve预先分配正确的权限元素数量。

  

当我在向量上调用shrink_to_fit或交换习惯用法时,向量容量确实减少了,但内存使用量很高,任何人都有想法解决这个问题?交换技巧应该是指针交换吗?

不,如果完全没有,它不会减少分配的内存!它将元素复制到一个新的向量(只有所需的大小)然后进行指针交换。因此,峰值内存更高,因为您暂时拥有所有元素的两个副本。

  

或map()。swap(),内存接近完全没有释放。

除非您使用交换技巧(或shrink_to_fit()),否则向量不会释放其内存,它会保留其当前容量,并且只有在清除它时才会减小其大小。要释放未使用的容量,您必须使用交换技巧或shrink_to_fit()。因此,所有内存仍归向量所有。

使用std::map的交换技巧毫无意义,地图永远不会保留未使用的已分配内存,因此您只需执行namesMap.clear()即可释放地图使用的所有内存。

总之,由于容器的工作原理,这一切都是完全可以预料到的。没有泄漏,你只是有无效的假设。