Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么删除的内存不能被重用 我在Windows 7上使用C++和MSVC 9,并且已经能够用MSVC 9在WindowsXP SP3上进行测试和复制。p>_C++_Windows 7_Dynamic Memory Allocation_Allocator - Fatal编程技术网

为什么删除的内存不能被重用 我在Windows 7上使用C++和MSVC 9,并且已经能够用MSVC 9在WindowsXP SP3上进行测试和复制。p>

为什么删除的内存不能被重用 我在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){

如果我分配1 GB的0.5 MB大小的对象,当我删除它们时,一切都正常,并按预期运行。但是,如果在删除对象时分配1 GB大小为0.25 MB的对象,内存将保持保留状态(黄色),从那时起,只能用于小于0.25 MB的分配

这个简单的代码将允许您通过更改哪个结构是typedef'd来测试这两个场景。分配和删除结构后,它将分配1GB的1MB字符缓冲区,以查看字符缓冲区是否会使用结构曾经占用的内存

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机器是否也有同样的问题

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

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

请注意,虽然您可能会认为这很奇怪,但在大多数程序(不是测试,而是现实生活中)中,内存使用模式是重复的:如果您请求一次100k块,那么您通常会再次请求。保留内存可以提高性能,并实际减少来自同一个bucket的所有请求的碎片

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


我通常不为windows编写代码,我甚至没有windows 7,所以我不能肯定地说是这样,但看起来确实是这样。

我可以在windows 7下用g++4.4.0确认相同的行为,因此它不在编译器中。事实上,当
getIterations()
返回
3590
或更多时,程序会失败——您会得到相同的截止值吗?这看起来像是Windows系统内存分配中的错误。对于知识渊博的灵魂来说,谈论内存碎片是很好的,但是这里所有的东西都被删除了,所以观察到的行为肯定不会发生。

使用您的代码,我执行了您的测试,得到了相同的结果。我怀疑大卫·罗德里格斯在这个案件中是对的

我做了测试,结果和你一样。似乎有可能出现这种“桶”行为

我也试过两种不同的测试。我没有使用1MB缓冲区分配1GB的数据,而是按照删除后第一次分配内存的方式进行分配。第二次测试,我分配了清理后的半兆缓冲区,然后分配了四兆缓冲区,每个缓冲区的总容量为512MB。最后,两个测试都有相同的内存结果,只有512被分配了一个没有大内存块的保留内存

正如David提到的,大多数应用程序倾向于进行相同大小的分配。但是,我们可以很清楚地看到为什么这会成为一个问题


也许解决这个问题的办法是,如果您以这种方式分配许多较小的对象,您最好分配一大块内存并自己管理它。然后,当您完成释放大的块时。

这是低碎片堆的副作用


你应该试着禁用它,看看是否有帮助。运行GetProcessHeap和CRT堆(以及您可能创建的任何其他堆)。

我与一些权威人士讨论了这个问题(Greg,如果您在那里,请说hi;D),并且可以确认David所说的基本正确

当堆在第一次分配过程中增长时