【问题标题】:C - Design your own free( ) functionC - 设计你自己的 free() 函数
【发布时间】:2011-08-22 11:55:06
【问题描述】:

今天我去面试,面试官问我这个,

  1. 告诉我步骤你将如何设计你自己的free( )函数 释放分配的内存。
  2. 怎么比C默认的free()函数效率更高呢?你能得出什么结论?

我很困惑,想不出设计的方式。

你们觉得呢?


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

【问题讨论】:

  • 您还需要自己的malloc 才能使这个有用,对吧?
  • 由于标准没有指定free 的实现,我看不出有人怎么可能回答2。
  • 你不能给出一个绝对的答案,但它确实创造了一个很好的话题——这可能就是重点!我同意您需要自己的 malloc ,否则没有重用内存的余地。确实指出这些“显而易见”的事情可能是他/她所追求的,然后是关于如何编写高效的动态内存分配系统(速度与内存等)的更深入讨论。记住:面试官不是想欺骗你,而是想看看你如何解决问题以及你知道什么。大声思考并要求澄清。向他们展示你所知道的!
  • 除非面试官不称职,否则我怀疑他们正在寻找更多用于存储和管理空闲块列表的算法......
  • 实际向操作系统请求内存只是malloc/free实现的一部分... C实际上向操作系统请求'大'块内存,然后保持一个链表“空闲”内存位置。当内存被释放时,它会返回到空闲列表。另请注意,实施的第 0 步是每年增加 4 万美元的薪水,这与维护极其难以调试的系统相关代码有关。

标签: c malloc free


【解决方案1】:

这实际上是一个非常模糊的问题,这可能就是您感到困惑的原因。他的意思是,给定现有的 malloc 实现,您将如何尝试开发一种更有效的方法来释放底层内存?还是他希望您开始讨论不同类型的 malloc 实现以及它们的好处和问题?他是否希望您知道虚拟内存在 x86 架构上的功能?

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

除了问自己的问题以获得澄清之外,很难说从哪里开始像这样模糊的问题。毕竟要设计自己的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 和 free 运行得快(或者有时甚至更慢,但可以预见地慢)。有dlmallocptmallocjemallocHoard's malloc 等等,其中许多都非常小而简洁,所以不要害怕阅读它们。如果我没记错的话,Kernighan 和 Ritchie 的“The C Programming Language”甚至使用了一个简单的 malloc 实现作为他们的示例之一。

【讨论】:

  • +1 并接受这个好答案......这与其他答案不同:-)
  • +1 表示指向 IBM 开发人员页面的链接。太棒了,文章补充了问题/答案。
【解决方案2】:

你不能盲目地设计free()而不知道malloc()是如何在后台工作的,因为你的free()的实现需要知道如何操作记账数据,而在不知道malloc()是如何实现的情况下这是不可能的.

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

【讨论】:

  • mallocfree(基本上是 dlmalloc)的最佳通用算法已广为人知,并且可以在几分钟内轻松表达,即使实现细节需要更多的努力。我只是解释一下。
【解决方案3】:

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

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

【讨论】:

  • +1 for >好处是您可以在几乎恒定的时间内进行分配,缺点是您的应用程序消耗的内存比实际需要的多。
【解决方案4】:

告诉我你将如何设计你自己的 free() 函数来释放分配的内存。

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

inline void my_free(void *ptr) { }

怎么比C默认的free()函数效率更高?

它非常快,需要零个机器周期。它还消除了释放后使用的错误。这是一个非常有用的free 函数,可用于实例化为短期批处理的程序;它可以有效地部署在某些生产环境中。

你能得出什么结论?

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

【讨论】:

    【解决方案5】:

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

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

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

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        malloc 和 free 应该遵循一种架构——本质上是一种允许不同策略共存的类架构。那么执行的free版本对应使用的malloc版本。

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

        【讨论】:

          【解决方案8】:

          malloc()的工作知识是实现free()所必需的。您可以在 K&R C 编程语言第 8 章第 8.7 节“示例——存储分配器”第 185 页中使用sbrk() 系统调用找到malloc()free() 的实现。 189.

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-12-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-06-27
            • 1970-01-01
            相关资源
            最近更新 更多