动态分配固定大小的类型

时间:2012-09-28 21:48:56

标签: c linux memory memory-management malloc

假设我们有一些固定长度的数据类型,例如C struct:

struct T
{
    ...;
}

分配T的一种方法是:

T* create_t() { return (T*) malloc(sizeof(T)); }

并解除分配:

void destroy_t(T* t) { free(t); }

引擎盖下,malloc使用内存分配算法,以不同的方式处理不同大小的块。

假设我们正在编写一个频繁调用create_t和destroy_t的程序,并且一次分配了很多T项(并且以伪随机顺序)。

鉴于所需的内存是固定大小的元素,是否可以编写一个优于malloc的通用实现的自定义内存分配方案。

例如,我们可以预先分配一个大小为T的元素的大数组,然后使用它们,但是跟踪哪些元素已分配哪些元素没有分配的最佳方法是什么?

当使用大量相同大小的分配调用时,Linux上的malloc最终会使用什么算法?

粗略地说,这种自定义方法的性能与通用malloc相比如何?

4 个答案:

答案 0 :(得分:2)

据我所知,所使用的内存管理是一种“桶”管理。

malloc将空闲内存段保留在桶中,并在调用时,尝试将最合适的块之一传递给调用者。

但是只需下载libc的源代码并自行完成。

编写内存管理非常棘手,并且已经在当前使用的算法中付出了很多努力。我确实认为,提出比这些人更好的东西是非常困难的(特别是作为一个人)。

答案 1 :(得分:2)

首先,您可以拥有malloc的多个实现。例如,Glibc malloc(解释here)是here,但musl libc malloc是hereC dynamic memory implementation的种类众所周知。

还要注意一个简单的实现

void *malloc (size_t sz)
{
   errno = ENNOMEM;
   return 0;
}

可能符合standard specification of malloc的字母,但不符合精神,(例如在Posix和C99中)。

实际上,malloc是通过向Linux kernel询问syscalls mmap(2)munmap(2),有时是sbrk(2)virtual memory来实现的malloc都与address spaceASLR相关。由于memory fragmentation malloc的结果可能与您的程序的一次运行不同。 GC_malloc能够处理相同大小的许多分配,但在很长时间运行的程序中最终会得到glib memory slices

您也可以使用例如像Boehm's conservative garbage collector中的切片分配器,但它可能很少有用。您也可以使用valgrind(例如,使用malloc代替free,而不是明确malloc - 明确您的数据。)

实际上,在Linux上,mmap运行良好。我认为你不应该为此烦恼。当然,它旨在最小化内存分配低级别操作,如malloc(这是昂贵的;良好的free实现管理良好的内存池并尝试重用malloc - 在从内核询问之前的内存)。还存在与多线程等相关的问题。

在考虑降低应用程序中malloc的成本之前,您应该对其进行衡量(memory arena非常有用,也可以调试malloc相关错误)。通常,{{1}}的成本在应用程序中并不重要。如果你真的想要,你可以管理自己的{{3}},但我不确定你应该打扰。 (优化前先测量)。在今天的机器上,缓存注意事项在代码的实际性能上也占主导地位。

答案 2 :(得分:2)

至于#1 - 其他人已经处理过,简而言之,glibc做得相当不错,其他mallocs在各种情况下都可能做得更好。

但是,关于你的第二个问题:自定义的如何执行?

•一般而言,自由列表分配器的手动编码,低级实现知道应用程序自己的使用模式和需求,可能会胜过像GNU libc提供的一般案例算法;

•但你必须通过写这件事来证明它。

顺便说一下,Custom malloc for lots of small, fixed size blocks?有一些相关的答案。

您还可以查看各种文件系统驱动程序中磁盘扇区使用情况的表示,因为它们有效地解决了相同的问题 - 在各种负载下以伪随机间隔分配固定大小的块/扇区 - 而大多数malloc将专注于是通用的。

答案 3 :(得分:0)

问:鉴于所需的内存是固定大小的元素,是否可以编写一个优于malloc的通用实现的自定义内存分配方案。?

答:可能。这可能是一项非常重要的任务。

任何给定的操作系统都可能具有不同的“malloc()”实现。 Linux(例如)的标准是Gnu Libc。你可以在这里找到来源:

'希望有所帮助!