首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >vector<string>以及map<string、int>在释放时可能出现故障?疑惑内存使用详细信息

vector<string>以及map<string、int>在释放时可能出现故障?疑惑内存使用详细信息
EN

Stack Overflow用户
提问于 2012-12-30 12:05:35
回答 1查看 677关注 0票数 1

我正在用c++编写代码来处理大量的流数据,这些数据包含了数百万节点的信息。我使用向量来存储每个节点的名称和用于索引的映射。

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

假设某个文件包含100万行,每行超过50个字符。将它们读入两次,然后检查进程的内存使用情况以及向量估计的内存使用情况。它们的大小不同,只有60 MB。这只是我遇到的更大问题的一个小投影,它可能在GB级别上有所不同。

我在64位Windows7 SP1旗舰版上使用Windows7 SP1编译带有x86设置的程序。

代码语言:javascript
运行
复制
#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版本如下:

代码语言:javascript
运行
复制
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()或向量(NamesVector).swap(NamesVector)习惯用法时,向量的容量确实减少了,但内存使用率却很高,有人有办法解决这个问题吗?交换技巧应该是指针交换吗?为什么它会涉及到内存、复制和所有东西,并导致这种情况?

代码语言:javascript
运行
复制
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.

当我为字符串索引添加映射时,发生了意外的行为。当我同时调用.swap().swap(NamesVector)和map().swap(namesMap)时,结果如下所示,这很好,因为内存被释放了。

代码语言:javascript
运行
复制
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.

但是当我只调用.swap().swap(NamesVector)时,内存被部分释放了。我的意思是它释放的部分比上面的结果要少,大约336MB。

代码语言:javascript
运行
复制
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),则内存几乎不会被释放。

代码语言:javascript
运行
复制
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.

我无法解释发生了什么。有人知道这里发生了什么吗?

谢谢你的帮助。

最好的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-12-30 22:31:05

内存泄漏标记在这里是不合适的,永远不会有任何内存泄漏--所有内存都是可访问的,并且由仍在作用域中的对象所有。内存泄漏意味着丢失的内存永远不会被释放,因为您没有对它的引用。

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

代码语言:javascript
运行
复制
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()来释放映射使用的所有内存。

总而言之,由于容器的工作方式,这完全是意料之中的。没有泄漏,你只是有无效的假设。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14088215

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档