为什么删除的内存无法重用

0xC*_*ACE 7 c++ allocator dynamic-memory-allocation windows-7

我在带有MSVC 9.0的Windows 7上使用C++,并且还能够在带有MSVC 9.0的Windows XP SP3上进行测试和再现.

如果我分配1 GB的0.5 MB大小的对象,当我删除它们时,一切正常并且按预期运行.但是,如果在删除它时分配1 GB的0.25 MB大小的对象,则内存保留(地址空间监视器中为黄色),从那时起,只能用于小于0.25 MB的分配.

这个简单的代码将允许您通过更改typedef的结构来测试这两种情况.在分配并删除了结构后,它将分配1 GB的1 MB char缓冲区,以查看char缓冲区是否将使用结构体曾经占用的内存.

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;
}
Run Code Online (Sandbox Code Playgroud)

您可以在下面的地址空间监视器中查看我的结果.让我强调,这两个最终结果之间的唯一区别是结构的大小被分配到1 GB标记.

季梅格 半梅格

这对我来说似乎是一个非常严重的问题,而且许多人可能会遭受这种问题甚至不知道.

  • 这是设计还是应该被视为一个错误?
  • 我可以让较小的删除对象实际上可以免费使用更大的分配吗?
  • 更多出于好奇,Mac或Linux机器是否遭受同样的问题?

Dav*_*eas 9

我不能肯定地说明这种情况,但这确实看起来像内存碎片(以其多种形式之一).在释放内存之后,分配器(malloc)可能会保留不同大小的存储桶以启用快速分配,而不是直接将其返回给操作系统,它会保留存储桶,以便以后可以处理相同大小的分配.同样的记忆.如果是这种情况,则存储器可用于相同大小的进一步分配.

这种类型的优化通常对对象禁用,因为即使不使用它也需要保留内存.如果阈值介于两种尺寸之间,则可以解释行为.

请注意,虽然您可能会觉得这很奇怪,但在大多数程序中(不是测试,而是现实生活),内存使用模式会重复出现:如果您要求100k块一次,那么通常会再次执行此操作.并保持记忆保留可以提高性能,实际上减少碎片,将来自所有请求从同一个桶理所当然的.

如果您想投入一些时间,可以通过分析行为来了解分配器的工作原理.编写一些测试,获取大小X,释放它,然后获取大小Y,然后显示内存使用情况.修复X的值并使用Y.如果两个大小的请求都是从相同的桶中授予的,则您将没有保留/未使用的内存(左侧的图像),而当从不同的桶授予大小时您会看到对右边图像的影响.

我通常不编写Windows代码,我甚至没有Windows 7,所以我不能肯定地说这是这种情况,但看起来确实如此.