什么算法适用于小内存块的连续重新分配?

时间:2018-06-06 14:10:38

标签: c memory memory-management dynamic-memory-allocation memory-fragmentation

在C程序中,我面临需要拥有大量内存块的事务,我需要知道是否有用于处理所有这些malloc / free的算法或最佳实践teqnique,我已经使用了数组来存储这些内存块,但在某些时候数组本身已满,重新分配数组只是更浪费,处理这个问题的优雅方法是什么?

2 个答案:

答案 0 :(得分:2)

在这种情况下,最好的算法是free list分配器+二叉搜索树。

您正在从系统中询问一个大内存块,然后从此块中分配固定大小的内存块。当块已满时,您将分配另一个,并将它们链接到红黑或AVL二进制搜索间隔树(否则通过遍历块列表在free期间搜索块会成为瓶颈)

同时,多线程和线程同步变得很重要。如果您只是使用互斥锁或简单的自旋锁,您会发现libc malloc的工作速度比自定义内存分配器快得多。解决方案可以在Hazard pointer中找到,即每个线程都有自己的内存分配器(或每个CPU内核一个分配器)。这将增加另一个问题 - 当一个线程分配内存而另一个线程释放它时,这将需要在自由函数期间搜索确切的分配器,以及strick锁定或无锁数据结构。

最佳选择 - 您可以使用jemalloctcmalloc或任何其他通用建议快速内存分配器来完全或部分替换您的libc(即pdmalloc)默认分配器。

答案 1 :(得分:2)

如果由于您提供的功能需要跟踪这些不同的缓冲区,那么您将需要某种缓冲区管理功能,包括为缓冲区管理分配内存。

但是,如果您担心内存碎片,那就是另一个问题。

我已经看过很多关于如何使用nilmalloc()导致内存碎片以及各种方法来减少或消除此问题的文章。

我怀疑多年前,这可能是一个问题。然而,现在我怀疑大多数程序员是否能够像开发现代编译器运行时的人那样在管理内存方面做得很好。我确信有特殊的应用程序,但编译器运行时开发非常了解内存碎片,并且他们使用了许多方法来帮助缓解这个问题。

例如,这是2010年的一篇较早的文章,描述了现代编译器运行时实现free()malloc()A look at how malloc works on the Mac

以下是GNU allocator

的内容

2004年11月来自IBM的这篇文章介绍了内存管理的一些注意事项,Inside memory management并提供了他们所称的"代码,用于简单实现malloc并免费帮助演示所涉及的内容管理记忆。"请注意,这是一个简单的示例,旨在说明一些问题,而不是当前实践的演示。

我使用Visual Studio 2015做了一个快速控制台应用程序,该应用程序在C源文件中调用C函数,该文件散布了各种大小的free()malloc()个调用。我在Windows任务管理器中查看进程时运行了这个。峰值工作集(内存)最大值为34MB。看着内存(私人工作集)测量,我看到它随着程序的运行起伏不定。

free()

程序员应该在#include <malloc.h> #include <stdio.h> void funcAlloc(void) { char *p[50000] = { 0 }; int i; for (i = 0; i < 50000; i+= 2) { p[i] = malloc(32 + (i % 1000)); } for (i = 0; i < 50000; i += 2) { free(p[i]); p[i] = 0; } for (i = 1; i < 50000; i += 2) { p[i] = malloc(32 + (i % 1000)); } for (i = 1; i < 50000; i += 2) { free(p[i]); p[i] = 0; } for (i = 0; i < 50000; i++) { p[i] = malloc(32 + (i % 1000)); } for (i = 0; i < 50000; i += 3) { free(p[i]); p[i] = 0; } for (i = 1; i < 50000; i += 3) { free(p[i]); p[i] = 0; } for (i = 2; i < 50000; i += 3) { free(p[i]); p[i] = 0; } } void funcMain(void) { for (int i = 0; i < 5000; i++) { funcAlloc(); } } malloc()搅拌内存的某些条件下练习帮助内存分配器的唯一考虑因素是使用一组标准缓冲区大小来处理不同长度的数据。

例如,如果要为不同大小的多个不同数据结构创建临时缓冲区,请对所有缓冲区使用最大free()的标准缓冲区大小,以便内存管理器正在使用相同的大小的内存块,因此它可以更有效地重用可用内存块。我已经看到一些动态数据结构功能使用这种方法,例如分配最小长度为32个字符的动态字符串,或者将缓冲区请求四舍五入为4或8的倍数。