假设我们有一些固定长度的数据类型,例如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相比如何?
答案 0 :(得分:2)
据我所知,所使用的内存管理是一种“桶”管理。
malloc
将空闲内存段保留在桶中,并在调用时,尝试将最合适的块之一传递给调用者。
但是只需下载libc的源代码并自行完成。
编写内存管理非常棘手,并且已经在当前使用的算法中付出了很多努力。我确实认为,提出比这些人更好的东西是非常困难的(特别是作为一个人)。
答案 1 :(得分:2)
首先,您可以拥有malloc
的多个实现。例如,Glibc malloc(解释here)是here,但musl libc malloc是here。 C 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 space和ASLR相关。由于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。你可以在这里找到来源:
'希望有所帮助!