malloc 的详细工作原理是什么?
how does malloc work in details?
我正在尝试查找有关 malloc 函数的一些有用信息。
当我调用这个函数时,它会动态分配内存。它 returns 指向已分配内存开头的指针(例如地址)。
问题:
如何使用返回的地址 read/write 进入分配的内存块(使用间接寻址寄存器或如何?)
如果无法分配内存块,则它 returns NULL。就硬件而言,NULL 是什么?
为了在堆中分配内存,我们需要知道哪些内存部分被占用了。这些信息(关于占用的内存)存储在哪里(例如,如果我们使用小型 RISC 微控制器)?
既然您使用的是 malloc,我们可以假设您使用的是 C 语言吗?
如果是这样,您将结果分配给一个指针变量,然后您可以通过引用该变量来访问内存。你真的不知道这是如何在汇编中实现的。这取决于您使用的 CPU。 malloc return 0 如果失败。由于通常 NULL 被定义为 0,因此您可以测试 NULL。您不关心 malloc 如何跟踪空闲内存。如果您确实需要此信息,您应该查看 glibc/malloc 中的源代码,可在网上找到
char * c = malloc(10); // allocate 10 bytes
if (c == NULL)
// handle error case
else
*c = 'a' // write a in the first character on the block
Q3 通常管理堆的方式是通过链表。在最简单的情况下,malloc 函数保留指向堆中第一个 free-space 块的指针,每个 free-space 块都有一个指向下一个空闲 space 的 header块在堆中。所以堆是 in-effect self-defining 就知道什么没有被占用(以及由此推断什么被占用)而言;这最大限度地减少了管理堆所需的开销 RAM 量。
当通过 malloc 调用需要新的 space 时,通过遍历链表找到足够大的 free-space 块。找到的 free-space 块被提供给 malloc 调用者(带有一个小的隐藏 header),如果需要,一个较小的 free-space 块被插入到链表中,其中包含任何残差 space 在原始空闲 space 块和 malloc 调用要求的内存量之间。
当一个堆块被应用程序释放时,它的块只是用linked-listheader格式化,并添加到链表中,通常有一些额外的逻辑来组合连续的free-space 块合并为一个更大的 free-space 块。
调试版本的 malloc 通常会做更多的事情,包括也保留 linked-list 分配的区域,"guard zones" 在分配的堆区域周围帮助检测内存溢出等。这些占用额外的堆space(就应用程序可用 space 而言,使堆有效变小),但在调试时非常有用。
Q2 NULL 指针实际上只是一个零,如果使用它会尝试访问从 RAM 的位置 0 开始的内存,这几乎总是 OS 的保留内存。这是大量内存违规中止的原因,所有这些都是由于程序员缺乏对分配内存的函数的 NULL returns 错误检查造成的)。
因为 non-OS 应用程序访问内存位置 0 从来都不是我们想要的,所以大多数硬件都会中止 non-OS 软件访问位置 0 的任何尝试。即使使用页面映射使得应用程序内存 space(包括位置 0)永远不会映射到实际 RAM 位置 0,因为 NULL 始终为零,大多数 CPU 仍然会中止访问位置 0 的尝试,假设这是通过包含 NULL 的指针进行访问。
鉴于您的 RISC 处理器,您将需要阅读其文档以了解它如何处理访问内存位置 0 的尝试。
Q1 有许多 high-level 语言方法可以使用分配的内存,主要是通过指针、字符串和数组。
就汇编语言和硬件本身而言,分配的堆块地址只是被放入一个用于内存间接寻址的寄存器中。您将需要了解 RISC 处理器是如何处理它的。但是,如果您使用 C 或 C++ 或此类更高级的语言,则无需担心寄存器;编译器会处理所有这些。
我正在尝试查找有关 malloc 函数的一些有用信息。 当我调用这个函数时,它会动态分配内存。它 returns 指向已分配内存开头的指针(例如地址)。 问题:
如何使用返回的地址 read/write 进入分配的内存块(使用间接寻址寄存器或如何?)
如果无法分配内存块,则它 returns NULL。就硬件而言,NULL 是什么?
为了在堆中分配内存,我们需要知道哪些内存部分被占用了。这些信息(关于占用的内存)存储在哪里(例如,如果我们使用小型 RISC 微控制器)?
既然您使用的是 malloc,我们可以假设您使用的是 C 语言吗? 如果是这样,您将结果分配给一个指针变量,然后您可以通过引用该变量来访问内存。你真的不知道这是如何在汇编中实现的。这取决于您使用的 CPU。 malloc return 0 如果失败。由于通常 NULL 被定义为 0,因此您可以测试 NULL。您不关心 malloc 如何跟踪空闲内存。如果您确实需要此信息,您应该查看 glibc/malloc 中的源代码,可在网上找到
char * c = malloc(10); // allocate 10 bytes
if (c == NULL)
// handle error case
else
*c = 'a' // write a in the first character on the block
Q3 通常管理堆的方式是通过链表。在最简单的情况下,malloc 函数保留指向堆中第一个 free-space 块的指针,每个 free-space 块都有一个指向下一个空闲 space 的 header块在堆中。所以堆是 in-effect self-defining 就知道什么没有被占用(以及由此推断什么被占用)而言;这最大限度地减少了管理堆所需的开销 RAM 量。
当通过 malloc 调用需要新的 space 时,通过遍历链表找到足够大的 free-space 块。找到的 free-space 块被提供给 malloc 调用者(带有一个小的隐藏 header),如果需要,一个较小的 free-space 块被插入到链表中,其中包含任何残差 space 在原始空闲 space 块和 malloc 调用要求的内存量之间。
当一个堆块被应用程序释放时,它的块只是用linked-listheader格式化,并添加到链表中,通常有一些额外的逻辑来组合连续的free-space 块合并为一个更大的 free-space 块。
调试版本的 malloc 通常会做更多的事情,包括也保留 linked-list 分配的区域,"guard zones" 在分配的堆区域周围帮助检测内存溢出等。这些占用额外的堆space(就应用程序可用 space 而言,使堆有效变小),但在调试时非常有用。
Q2 NULL 指针实际上只是一个零,如果使用它会尝试访问从 RAM 的位置 0 开始的内存,这几乎总是 OS 的保留内存。这是大量内存违规中止的原因,所有这些都是由于程序员缺乏对分配内存的函数的 NULL returns 错误检查造成的)。
因为 non-OS 应用程序访问内存位置 0 从来都不是我们想要的,所以大多数硬件都会中止 non-OS 软件访问位置 0 的任何尝试。即使使用页面映射使得应用程序内存 space(包括位置 0)永远不会映射到实际 RAM 位置 0,因为 NULL 始终为零,大多数 CPU 仍然会中止访问位置 0 的尝试,假设这是通过包含 NULL 的指针进行访问。
鉴于您的 RISC 处理器,您将需要阅读其文档以了解它如何处理访问内存位置 0 的尝试。
Q1 有许多 high-level 语言方法可以使用分配的内存,主要是通过指针、字符串和数组。
就汇编语言和硬件本身而言,分配的堆块地址只是被放入一个用于内存间接寻址的寄存器中。您将需要了解 RISC 处理器是如何处理它的。但是,如果您使用 C 或 C++ 或此类更高级的语言,则无需担心寄存器;编译器会处理所有这些。