在我释放内存之前,使用malloc会更快吗?

3
当我分配和释放内存后,然后分配的内存大小恰好等于之前释放的部分大小,那么第二次分配会比第一次更快吗?这可能是因为它已经知道了一个空闲的内存区域,还是因为堆的这个部分仍然被分配给进程?或者还有其他可能的优势吗?或者通常没有什么区别吗?
编辑:如评论中所询问:
  • 我特别关注gcc和MSVC。
  • 我的假设是在操作系统中未“收回”该内存。
由于具体实现细节涉及很多内容,我想让它更加清晰明了,这只是一个假设性问题。我不打算滥用它,但我只是想知道是否可能发生这种情况以及假设速度提升的原因是什么。

5
这是一个实现细节,因此您需要指定特定的编译器 - gcc、MSVC或其他。 - sashoalm
还有很多malloc的实现,比如jemalloctcmalloc - ymonad
我认为这甚至不依赖于操作系统,因为尽管通常存在“回收”时间,但在某些情况下,任何其他应用程序都可以请求已释放的内存。 - Carles
@ymonad从未考虑过这一点,但是确实有道理,不只有一个malloc...但这更多是理论问题而非实现问题。如果某些实现使用了这样的技术,我想知道。并不是说我特别想滥用它们。 - Kami Kaze
你可能不需要担心这个。 - Jabberwocky
显示剩余6条评论
3个回答

3
在一些常见平台上,例如GCC x86_64,有两种malloc():传统的用于小型分配,以及mmap用于大型分配。基于mmap的大型内存分配将具有较少的相互依赖性。但是,传统的小型内存分配在先前已经free()时,在某些情况下确实会经历巨大的加速。
这是因为正如您所建议的那样,free()不会立即将内存返回给操作系统。事实上,通常无法这样做,因为内存可能位于连续的堆中间。因此,在许多系统(但不是所有系统)上,malloc()只有在需要请求更多堆空间时才会变慢。

3
使用malloc进行内存分配时,避免调用像sbrkmmap这样的系统调用,可以更快地进行内存分配。至少可以避免一次上下文切换
尝试运行以下程序的实验结果。
#include <stdlib.h>

int main() {

    void* x = malloc(1024*1024);
    free(x);
    x = malloc(1024*1024);

}

要运行它,请使用命令strace ./a.out

当你删除free调用时,你会注意到两个额外的系统调用brk


“malloc()” 总是使用 “sbrk()” 的假设是错误的。 “malloc()” 的实现可以改用 “mmap()” 或其他合适的机制。 - DevSolar
无论使用哪个系统调用,它仍然是一个额外的系统调用,可以避免这一点。 - Grzegorz Żur
除非在不影响系统的情况下,否则我不喜欢这种笼统的说法。(虽然这不是我的负评。) - DevSolar
1
答案虽然部分符合我的问题。我知道(并且我希望我已经表明了)没有“这总是情况”,但“在正确的情况下可能会发生这种情况”。 - Kami Kaze

2
以下是我在-O1编译时编译的简单基准测试结果:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv){
    for(int i=0;i<10000000;i++){
        char  volatile * p = malloc(100);
        if(!p) { perror(0); exit(1); }
        *p='x';
        //free((char*)p);
    }

    return 0;
}

在我的Linux系统上,一个迭代使用免费的60ns左右,而不使用免费的150ns左右。是的,释放后的动态内存分配可能会更快。

这取决于所分配的大小。这些小尺寸不会被返回到操作系统中。对于2的幂次方较大的尺寸,glibc malloc开始mmap和unmmapping,然后我预计在释放变体中出现减速。


我认为这并不能证明什么,因为实际的分配可能会被延迟到你使用该内存的时候才进行。在你的循环中添加p[0] = i; - Lundin
@Lundin 我最初使用了 char volatile *p。但是没有显著的差异,所以我将其删除了。现在重新添加了它。 - Petr Skocik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接