我正在用c++编写代码来处理大量的流数据,这些数据包含了数百万节点的信息。我使用向量来存储每个节点的名称和用于索引的映射。
现在的问题是,向量占用的内存比预期的要多得多,它们的破坏是无法解释的。
假设某个文件包含100万行,每行超过50个字符。将它们读入两次,然后检查进程的内存使用情况以及向量估计的内存使用情况。它们的大小不同,只有60 MB。这只是我遇到的更大问题的一个小投影,它可能在GB级别上有所不同。
我在64位Windows7 SP1旗舰版上使用Windows7 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()或向量(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.
当我为字符串索引添加映射时,发生了意外的行为。当我同时调用.swap().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.
但是当我只调用.swap().swap(NamesVector)时,内存被部分释放了。我的意思是它释放的部分比上面的结果要少,大约336MB。
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.
我无法解释发生了什么。有人知道这里发生了什么吗?
谢谢你的帮助。
最好的。
发布于 2012-12-30 22:31:05
内存泄漏标记在这里是不合适的,永远不会有任何内存泄漏--所有内存都是可访问的,并且由仍在作用域中的对象所有。内存泄漏意味着丢失的内存永远不会被释放,因为您没有对它的引用。
在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()
来释放映射使用的所有内存。
总而言之,由于容器的工作方式,这完全是意料之中的。没有泄漏,你只是有无效的假设。
https://stackoverflow.com/questions/14088215
复制相似问题