草庐IT

关于 malloc:C – 设计自己的 free() 函数

codeneng 2023-03-28 原文

C - Design your own free( ) function

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

  • Tell me the steps how will you design your own free( ) function for
    deallocate the allocated memory.
  • How can it be more efficient than C's default free() function ? What can you conclude ?
  • 我很困惑,想不出设计的方式。

    你们觉得呢?

    编辑:既然我们需要了解 malloc() 是如何工作的,你能告诉我编写我们自己的 malloc() 函数

    的步骤吗?

    • 您还需要自己的 malloc 才能使此功能有用,对吗?
    • 由于标准没有指定 free 的实现,我看不出任何人怎么可能回答 2。
    • 你不能给出一个绝对的答案,但它确实创造了一个很好的话题——这可能就是重点!我同意你需要你自己的 malloc 否则没有空间来重用内存。确实指出这些"显而易见"的事情可能是他/她所追求的,然后是关于如何编写高效的动态内存分配系统(速度与内存等)的更深入讨论。记住:面试官不是想欺骗你,而是想看看你如何解决问题以及你知道什么。大声思考并要求澄清。向他们展示你所知道的!
    • mallocfree 的实现不能由标准指定,因为在嵌入式平台上开发时可能的实现取决于操作系统或编译器,其中编译器模拟您对内存管理功能的使用(没有 malloc/free 是实际执行,因为无论如何所有内存都属于您的小型操作系统)
    • 我相信 malloc() 如何工作应该是一个单独的问题。
    • ?
    • 你不能盲目地设计 free() 而不知道 malloc() 是如何工作的,因为你的 free() 实现需要知道如何操作簿记数据,而在不知道如何操作的情况下这是不可能的malloc() 已实现。

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

      434511

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

      434511

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

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

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

      434511

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

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

      434511

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

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

      434511

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

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

      除了开始问自己的问题以获得澄清之外,很难说从哪里开始像这样模糊的问题。毕竟要设计自己的free函数,首先要知道malloc是如何实现的。所以很有可能,问题实际上是关于您是否知道如何实现 malloc。

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

      对于初学者来说,查看这篇名为"内部内存管理"的 IBM DeveloperWorks 文章。

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

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

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

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

      不过,这是一个真正简单的实现 malloc 的方法。你可以想象,有很多可能的方法可以将你的内存分成块然后管理这些块。有多少数据结构和算法就有多少方法。它们也都是为不同的目的而设计的,比如限制由于小的、已分配的块与小的、未分配的块混合而导致的碎片,或者确保 malloc 和 free 运行得快(或者有时甚至更慢,但可以预见地慢)。有 dlmalloc、ptmalloc、jemalloc、Hoard 的 malloc 等等,其中许多都非常小而简洁,所以不要害怕阅读它们。如果我没记错的话,Kernighan 和 Ritchie 的"The C Programming Language"甚至使用了一个简单的 malloc 实现作为他们的示例之一。

      434511

      malloc()的工作知识是实现free()所必需的。您可以使用 K 中的 sbrk() 系统调用找到 malloc()free() 的实现

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

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

      434511

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

      434511

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

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

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

      434511

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

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

      434511

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

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

      434511

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

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

      除了开始问自己的问题以获得澄清之外,很难说从哪里开始像这样模糊的问题。毕竟要设计自己的free函数,首先要知道malloc是如何实现的。所以很有可能,问题实际上是关于您是否知道如何实现 malloc。

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

      对于初学者来说,查看这篇名为"内部内存管理"的 IBM DeveloperWorks 文章。

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

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

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

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

      不过,这是一个真正简单的实现 malloc 的方法。你可以想象,有很多可能的方法可以将你的内存分成块然后管理这些块。有多少数据结构和算法就有多少方法。它们也都是为不同的目的而设计的,比如限制由于小的、已分配的块与小的、未分配的块混合而导致的碎片,或者确保 malloc 和 free 运行得快(或者有时甚至更慢,但可以预见地慢)。有 dlmalloc、ptmalloc、jemalloc、Hoard 的 malloc 等等,其中许多都非常小而简洁,所以不要害怕阅读它们。如果我没记错的话,Kernighan 和 Ritchie 的"The C Programming Language"甚至使用了一个简单的 malloc 实现作为他们的示例之一。

      434511

      malloc()的工作知识是实现free()所必需的。您可以使用 K 中的 sbrk() 系统调用找到 malloc()free() 的实现


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

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

    除了开始问自己的问题以获得澄清之外,很难说从哪里开始像这样模糊的问题。毕竟要设计自己的free函数,首先要知道malloc是如何实现的。所以很有可能,问题实际上是关于您是否知道如何实现 malloc。

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

    对于初学者来说,查看这篇名为"内部内存管理"的 IBM DeveloperWorks 文章。

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

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

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

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

    不过,这是一个真正简单的实现 malloc 的方法。你可以想象,有很多可能的方法可以将你的内存分成块然后管理这些块。有多少数据结构和算法就有多少方法。它们也都是为不同的目的而设计的,比如限制由于小的、已分配的块与小的、未分配的块混合而导致的碎片,或者确保 malloc 和 free 运行得快(或者有时甚至更慢,但可以预见地慢)。有 dlmalloc、ptmalloc、jemalloc、Hoard 的 malloc 等等,其中许多都非常小而简洁,所以不要害怕阅读它们。如果我没记错的话,Kernighan 和 Ritchie 的"The C Programming Language"甚至使用了一个简单的 malloc 实现作为他们的示例之一。

    • 1 并接受这个好答案……这与其他答案不同:-)
    • 1 用于指向 IBM 开发人员页面的链接。太棒了,文章补充了问题/答案。


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

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

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


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

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

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


    n


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

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

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


    malloc()的工作知识是实现free()所必需的。您可以使用 K 中的 sbrk() 系统调用找到 malloc()free() 的实现


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

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


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

    有关关于 malloc:C – 设计自己的 free() 函数的更多相关文章

    1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

      我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

    2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

      我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

    3. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

      我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

    4. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

      我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

    5. ruby - 在 Ruby 中有条件地定义函数 - 2

      我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

    6. ruby - 在 Ruby 中按名称传递函数 - 2

      如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

    7. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

      说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

    8. LC滤波器设计学习笔记(一)滤波电路入门 - 2

      目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

    9. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

      项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

    10. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

      我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

    随机推荐