C - 设计你自己的free()函数

时间:2011-08-22 11:55:07

标签: c malloc free

今天,我出现在面试中,面试官问我这个,

  
      
  1. 告诉我步骤您将如何设计自己的free( )功能   释放分配的内存。
  2.   
  3. 如何比C的默认free()功能更有效?你能得出什么结论?
  4.   
我很困惑,想不出设计的方式。

你觉得怎么样?


编辑:由于我们需要了解malloc()的工作原理,您能告诉我编写自己的malloc()函数的步骤

8 个答案:

答案 0 :(得分:14)

这实际上是一个非常模糊的问题,这可能就是你迷茫的原因。他是否意味着,鉴于现有的malloc实现,您将如何尝试开发一种更有效的方式来释放底层内存?或者他是否期望你开始讨论不同类型的malloc实现及其好处和问题?他是否希望您了解虚拟内存在x86架构上的功能?

此外,通过提高效率,他是指更节省空间还是更节省时间? free()必须是确定性的吗?是否必须尽可能多地将内存返回给操作系统,因为它处于低内存,多任务环境中?我们的标准是什么?

除了开始提出自己的问题以获得澄清之外,很难说从哪个模糊的问题开始。毕竟,为了设计自己的自由函数,首先必须知道如何实现malloc。很有可能,问题在于你是否知道如何实施malloc。

如果您不熟悉内存管理的内部,开始理解malloc如何实现的最简单方法是首先编写自己的内存。

首先查看this IBM DeveloperWorks article called "Inside Memory Management"

但在你编写自己的malloc / free之前,首先需要内存来分配/释放。不幸的是,在受保护模式的操作系统中,您无法直接寻址机器上的内存。那你怎么得到它?

你问操作系统。借助x86的虚拟内存功能,操作系统可以将任何RAM或交换内存映射到内存地址。您的程序所看到的内存可能在整个系统中都是碎片化的,但是由于内核的虚拟内存管理器,它看起来都是一样的。

内核通常提供系统调用,允许您为进程映射额外的内存。在较旧的UNIX操作系统上,这通常是brk / sbrk将堆内存增加到进程的边缘或将其缩小,但是很多系统还提供了mmap / munmap来简单地映射大块的堆内存。这只是你的一次可以访问一个大的,连续的内存块,你需要malloc / free来管理它。

一旦你的进程有一些可用的堆内存,它就是将它分成块,每个块包含它自己的元信息,包括它的大小和位置,是否已经分配,​​然后管理这些块。一个简单的结构列表,每个结构包含元信息和大量字节的一些字段,可以工作,在这种情况下,malloc必须遍历列表,直到找到足够大的未分配块(或它可以组合的块),并且然后如果找不到足够大的块,则映射到更多内存。找到块后,只需返回指向数据的指针即可。然后,free()可以使用该指针将几个字节反转回结构中存在的成员字段,然后可以修改它(即标记chunk.allocated = false;)。如果列表末尾有足够的未分配块,您甚至可以从列表中删除它们并取消映射或缩小进程堆中的内存。

这是实现malloc的一种非常简单的方法。可以想象,有很多可能的方法可以将内存分成块然后管理这些块。数据结构和算法的方法有很多种。它们都是为不同的目的而设计的,比如限制由于小的,分配的块与小的,未分配的块混合的碎片,或者确保malloc和自由运行快速(或者有时甚至更慢,但可预测地缓慢)。那里有dlmallocptmallocjemallocHoard's malloc等等,其中很多都非常小而且简洁,所以不要害怕阅读它们。如果我没记错的话,Kernighan和Ritchie的“C编程语言”甚至使用一个简单的malloc实现作为他们的例子之一。

答案 1 :(得分:8)

你不能盲目地设计free()而不知道malloc()如何在幕后工作,因为你free()的实现需要知道如何操纵簿记数据,这是不可能的,如果不知道如何实施malloc()

所以一个不可回答的问题可能是如何设计malloc()和free()而不是一个简单的问题,但你可以部分回答它,例如通过提出一些非常简单的实现内存池当然不等于malloc()但会表明你的知识存在。

答案 2 :(得分:3)

当您只能访问用户空间(通常称为内存池)时,一种常见方法是在应用程序启动时从操作系统获取大量内存。您的malloc需要检查该池的正确大小的哪些区域仍然是空闲的(通过某种数据结构)并分发指向该内存的指针。您的free需要在数据结构中将内存标记为空闲,并且可能需要检查池的碎片。

好处是您可以在几乎恒定的时间内进行分配,缺点是您的应用程序消耗的内存比实际需要的内存多。

答案 3 :(得分:1)

内存使用模式可能是一个因素。 free的默认实现不能假设您分配/解除分配的频率以及分配时的大小。

例如,如果经常分配和释放大小相似的对象,则可以通过使用内存池来提高速度,内存效率和减少碎片。

编辑:正如尖锐的指出,只有将free和malloc设计在一起才有意义。所以首先要弄清楚malloc是如何实现的。

答案 4 :(得分:1)

  

告诉我你将如何设计自己的free()函数来解除分配内存的步骤。

#include <stdlib.h>
#undef free
#define free(X) my_free(X)

inline void my_free(void *ptr) { }
  

它如何比C&#39的默认free()函数更有效?

速度非常快,需要零机器周期。它还会使免费使用后的漏洞消失。它是一个非常有用的free函数,用于程序,它被实例化为短期批处理过程;它可以在某些生产环境中有效地部署。

  

你能得出什么结论?

我真的想要这份工作,但在另一家公司。

答案 5 :(得分:0)

如果您的应用要在操作系统之上运行,则

mallocfree才有意义。如果您想编写自己的内存管理函数,您必须知道如何从该特定操作系统请求内存,或者您可以使用现有的malloc立即保留堆内存,然后使用您自己的函数来分发/通过你的应用程序重新分配已分配的内存

答案 6 :(得分:0)

有一个malloc和free应该遵循的架构 - 本质上是允许不同策略共存的类架构。然后执行的free版本对应于使用的malloc版本。

但是,我不确定这种架构的观察频率。

答案 7 :(得分:0)

malloc()的工作知识是实施free()的必要条件。您可以使用K&amp; R C编程语言中的malloc()系统调用找到free()sbrk()的实现第8章,第8.7节“示例 - 存储分配器“pp.185-189。