为什么删除的内存不能被重用 我在Windows 7上使用C++和MSVC 9,并且已经能够用MSVC 9在WindowsXP SP3上进行测试和复制。p>
如果我分配1 GB的0.5 MB大小的对象,当我删除它们时,一切都正常,并按预期运行。但是,如果在删除对象时分配1 GB大小为0.25 MB的对象,内存将保持保留状态(黄色),从那时起,只能用于小于0.25 MB的分配 这个简单的代码将允许您通过更改哪个结构是typedef'd来测试这两个场景。分配和删除结构后,它将分配1GB的1MB字符缓冲区,以查看字符缓冲区是否会使用结构曾经占用的内存为什么删除的内存不能被重用 我在Windows 7上使用C++和MSVC 9,并且已经能够用MSVC 9在WindowsXP SP3上进行测试和复制。p>,c++,windows-7,dynamic-memory-allocation,allocator,C++,Windows 7,Dynamic Memory Allocation,Allocator,如果我分配1 GB的0.5 MB大小的对象,当我删除它们时,一切都正常,并按预期运行。但是,如果在删除对象时分配1 GB大小为0.25 MB的对象,内存将保持保留状态(黄色),从那时起,只能用于小于0.25 MB的分配 这个简单的代码将允许您通过更改哪个结构是typedef'd来测试这两个场景。分配和删除结构后,它将分配1GB的1MB字符缓冲区,以查看字符缓冲区是否会使用结构曾经占用的内存 struct HalfMegStruct { HalfMegStruct():m_Next(0){
struct HalfMegStruct
{
HalfMegStruct():m_Next(0){}
/* return the number of objects needed to allocate one gig */
static int getIterations(){ return 2048; }
int m_Data[131071];
HalfMegStruct* m_Next;
};
struct QuarterMegStruct
{
QuarterMegStruct():m_Next(0){}
/* return the number of objects needed to allocate one gig */
static int getIterations(){ return 4096; }
int m_Data[65535];
QuarterMegStruct* m_Next;
};
// which struct to use
typedef QuarterMegStruct UseType;
int main()
{
UseType* first = new UseType;
UseType* current = first;
for ( int i = 0; i < UseType::getIterations(); ++i )
current = current->m_Next = new UseType;
while ( first->m_Next )
{
UseType* temp = first->m_Next;
delete first;
first = temp;
}
delete first;
for ( unsigned int i = 0; i < 1024; ++i )
// one meg buffer, i'm aware this is a leak but its for illustrative purposes.
new char[ 1048576 ];
return 0;
}
struct-HalfMegStruct
{
HalfMegStruct():m_Next(0){}
/*返回分配一个gig所需的对象数*/
静态int getIterations(){return 2048;}
国际货币单位数据[131071];
HalfMegStruct*m_Next;
};
结构
{
QuarterMegStruct():m_Next(0){}
/*返回分配一个gig所需的对象数*/
静态int getIterations(){return 4096;}
国际货币单位数据[65535];
QuarterMegStruct*m_Next;
};
//要使用哪个结构
typedef-QuarterMegStruct-UseType;
int main()
{
UseType*first=新的UseType;
UseType*当前=第一个;
对于(int i=0;im_Next=新使用类型;
while(第一个->下一个)
{
UseType*temp=first->m_Next;
首先删除;
第一个=温度;
}
首先删除;
for(无符号整数i=0;i<1024;++i)
//一个meg缓冲区,我知道这是一个漏洞,但出于说明目的。
新字符[1048576];
返回0;
}
下面你可以从内部看到我的结果。让我强调一下,这两个最终结果之间的唯一区别是分配给1GB标记的结构的大小
对我来说,这似乎是一个相当严重的问题,许多人可能正在遭受这一问题的折磨,甚至不知道这一点
- 那么这是出于设计还是应该被视为一个bug
- 我可以让删除的小对象实际上免费供较大的分配使用吗
- 更令人好奇的是,Mac或Linux机器是否也有同样的问题
我通常不为windows编写代码,我甚至没有windows 7,所以我不能肯定地说是这样,但看起来确实是这样。我可以在windows 7下用g++4.4.0确认相同的行为,因此它不在编译器中。事实上,当
getIterations()
返回3590
或更多时,程序会失败——您会得到相同的截止值吗?这看起来像是Windows系统内存分配中的错误。对于知识渊博的灵魂来说,谈论内存碎片是很好的,但是这里所有的东西都被删除了,所以观察到的行为肯定不会发生。使用您的代码,我执行了您的测试,得到了相同的结果。我怀疑大卫·罗德里格斯在这个案件中是对的
我做了测试,结果和你一样。似乎有可能出现这种“桶”行为
我也试过两种不同的测试。我没有使用1MB缓冲区分配1GB的数据,而是按照删除后第一次分配内存的方式进行分配。第二次测试,我分配了清理后的半兆缓冲区,然后分配了四兆缓冲区,每个缓冲区的总容量为512MB。最后,两个测试都有相同的内存结果,只有512被分配了一个没有大内存块的保留内存
正如David提到的,大多数应用程序倾向于进行相同大小的分配。但是,我们可以很清楚地看到为什么这会成为一个问题
也许解决这个问题的办法是,如果您以这种方式分配许多较小的对象,您最好分配一大块内存并自己管理它。然后,当您完成释放大的块时。这是低碎片堆的副作用
你应该试着禁用它,看看是否有帮助。运行GetProcessHeap和CRT堆(以及您可能创建的任何其他堆)。我与一些权威人士讨论了这个问题(Greg,如果您在那里,请说hi;D),并且可以确认David所说的基本正确 当堆在第一次分配过程中增长时