我在带有 MSVC 9.0 的 Windows 7 上使用 C++,并且还能够在带有 MSVC 9.0 的 Windows XP SP3 上进行测试和重现。
如果我分配 1 GB 0.5 MB 大小的对象,当我删除它们时,一切正常并且行为符合预期。但是,如果我在删除对象时分配 1 GB 0.25 MB 大小的对象,则内存仍保留保留(黄色地址空间监视器 http://hashpling.org/asm/),从那时起将只能用于小于 0.25 MB 的分配。
这个简单的代码将让您通过更改类型定义的结构来测试这两种情况。分配并删除结构后,它将分配 1 GB 的 1 MB 字符缓冲区,以查看字符缓冲区是否将使用结构曾经占用的内存。
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;
}
下面你可以看到我的结果地址空间监视器 http://hashpling.org/asm/。让我强调一下这两个最终结果之间的唯一区别是分配到 1 GB 标记的结构的大小.
对我来说,这似乎是一个相当严重的问题,许多人可能正在遭受这个问题,但他们甚至不知道这一点。
- 这是设计使然还是应该被视为错误?
- 我可以让小的已删除对象实际上可供更大的分配使用吗?
- 更令人好奇的是,Mac 或 Linux 机器是否也会遇到同样的问题?
我不能肯定地说情况确实如此,但这确实看起来像内存碎片(以多种形式之一)。分配器(malloc)可能会保留不同大小的存储桶以实现快速分配,在释放内存后,它不会直接将其返回给操作系统,而是保留存储桶,以便可以从以后处理相同大小的分配。相同的记忆。如果是这种情况,则该内存将可用于相同大小的进一步分配。
这类优化,通常被禁用big对象,因为它需要保留即使没有使用内存。如果阈值介于两个尺寸之间,则可以解释该行为。
请注意,虽然您可能认为这很奇怪,但在大多数程序(不是测试,而是现实生活)中,内存使用模式都是重复的:如果您一次请求 100k 块,那么您通常会再次这样做。并保留记忆reserved可以提高性能并且实际上reduce来自同一存储桶授予的所有请求的碎片。
如果您想投入一些时间,可以通过分析行为来了解分配器的工作原理。编写一些测试,将获取大小 X,释放它,然后获取大小 Y,然后显示内存使用情况。修复 X 的值并使用 Y。如果从相同的存储桶授予两种大小的请求,您将不会有保留/未使用的内存(左图),而当从不同的存储桶授予大小时,您将看到右图的效果。
我通常不会为 Windows 编写代码,而且我什至没有 Windows 7,所以我不能肯定地说情况就是如此,但看起来确实如此。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)