【问题标题】:Dynamically allocate memory in Assembly?在Assembly中动态分配内存?
【发布时间】:2017-10-20 06:57:52
【问题描述】:

如果我想分配未知大小的动态内存部分,或者更确切地说是在运行时已知的大小,在用户输入他想要分配的兆字节数之后,例如,最好的方法是什么?去做?是否从 C 中调用“malloc”,要求操作系统为我这样做?或者,还有更好的方法? 通常是怎么做的?

注意我不想预订

【问题讨论】:

  • 调用 malloc 或 mmap,就像你从 C 中一样,或者像 C 编译器在它从你的 C 生成的 asm 中所做的那样。(或 realloc / calloc / aligned_alloc /随便。)最好的方法取决于你在做什么。
  • malloc 是 C 库中的一个函数。如果您不想将其链接到您的程序,您可以使用通常为sbrkmmap 的底层系统调用。但是您的问题缺乏上下文,无法在本网站上被接受。
  • 相关非 Linux 示例:avr-libc(用于在 8 位 RISC AVR 架构上运行的裸机程序)实现 malloc this way。有关分配器如何工作和管理其空闲列表的信息,请参阅最后的“实现细节”部分。您当然可以在 Linux(在任何架构上)的用户空间中执行类似的操作如果您想实现自己的分配器。但通常没有理由这样做,只需致电aligned_alloc。尽管通常任何值得在 asm 中编写以实现高性能的循环都避免了动态分配。
  • 即“通常如何完成”的答案:根本不是来自asm。仅在 asm 中编写代码中真正对性能至关重要的部分。例如,请参阅 x264ffmpeg,其中大部分代码是用 C 语言编写的,只有少数 SIMD 或其他函数是用 asm 手写的。
  • 在我们用汇编语言编写应用程序的时候,PC-DOS 是一个单用户系统,默认情况下你会获得所有内存。所以这不是问题。现在我会用 C 或其他语言编写主程序,设置环境,然后可能调用一些程序集来完成非常专门的任务。从汇编调用malloc 并不比从C 调用它快,只是更难。

标签: linux assembly memory-management


【解决方案1】:

另一种方法是定义尽可能大的静态数组并编写自己的malloc/free 子程序。这很简单,特别是如果分配的块没有多线程或其他类型的共享使用。您保留第一个空块的地址,并在每个块的开头存储块的大小和下一个空闲块的地址。

PS:分配(保留)块也包含块大小作为前缀。此处不使用下一个块的地址,可以为 0 作为“保留”内存的标志。更简单的解决方案是只有块大小和标志 free/used_block 但这样你必须扫描多个保留块直到到达比只有空闲块链慢的空闲块。

【讨论】:

  • 如果您要实现自己的 malloc/free,您通常会在 sbrk 和/或 mmap 系统调用之上执行此操作,以便在您的系统调用时从操作系统获取更多内存空闲列表为空。使用巨大的静态数组,一旦内存被触摸,您就永远无法将内存返回给操作系统。 (除了阵列页面上的munmap / mmap。)
  • 老实说,这对于“玩具”程序来说并不是一个糟糕的答案。这不是一个好的设计,但它非常简单,并且对于初学者来说可能很容易在 asm 中实现。 (这不是我的反对票)。顺便说一句,您描述的细节似乎需要释放函数提供块的大小,因此它与 malloc/free API 不同。
  • 这是替代方式,取决于 OP 的需求。但是如果有人不喜欢它并且认为它不严重,让他(或她)认为OP为什么要在汇编中为Linux编写程序......mmap 在上面的cmets中已经提到过,我不得不说其他的东西不要重复。关于初始 mmap / munmap 数组分配 - 当然可以,但如果 R​​AM 需求较低(例如总共 10-20MB),也可以静态保留。
  • 如果您要发布答案,您可以重复(并扩展)来自 cmets 的任何/所有好的建议。实际上鼓励将 answer-cmets 变成正确的答案。我只是评论,因为问题太模糊,不知道什么样的答案是合适的,但如果你要发布一个,你一定要提到mmapsbrk
  • @PeterCordes 我开始写评论,然后决定将其发布为答案,因为:1)它是可能的解决方案之一,不是最好的或推荐的,但也不建议在汇编中写下Linux; 2)因为评论太长了。您对mmap 的看法是对的,但将其告诉有问题的 cmets - 为什么它们不是答案?无论如何,如果 OP 想学习汇编而不是开发“严肃”软件,他可能会选择我的解决方案而不是 mmap
【解决方案2】:

mmap2 和 brk 系统调用是在汇编中执行此操作的最简单方法。 mmap2 系统调用在汇编中更难使用,但如果您需要大量动态分配的内存,这是要走的路。 brk 易于使用,它通过移动“程序中断”(程序内存空间的边界)有效地为您的程序分配更多内存来工作。如果您需要少量动态内存(例如,少于一整页),这是一种可行的方法。

【讨论】:

  • malloc 是一个 c 库函数,而不是系统调用。 Malloc 基本上包装了 brk 和 mmap2 系统调用,但它也保留了有关已分配内存的内部信息,以供以后的 malloc 调用或 free 调用使用。如果你喜欢 c 库,你只能使用 malloc。
  • 但它更简单,而且从 assemlby 使用它的开销也不大,不是吗?
  • malloc 是最简单的。使用 it 汇编与 C 相比没有性能开销——它们都是直接的函数调用。相对于其他一些定制的分配策略,当然可能会有开销。如果您出于某种原因在汇编中编写了很多代码,那么链接并使用 C 库将非常有用,以避免在您需要随机实用程序函数时重新发明轮子。
  • 有人可能会争辩说,mmapmalloc 一样简单——但您必须以 4K 的页面大小为单位请求内存。
  • 我认为您可以就性能提出合理的论据!例如,您说调用通用malloc 可能比非常简单的分配器要慢 - 如果您的用例适合简单的话。不过,您仍然需要构建一个分配器:调用brk()(我认为您更可能实际使用sbrk())或mmap 通常会比malloc,因为每次都是系统调用。因此,为了提高性能,您必须在其之上实现某种分配器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 2013-07-01
相关资源
最近更新 更多