malloc 需要 OS 支持吗?

Does malloc needs OS support?

内存管理是底层操作系统提供的一项服务。当我们调用 malloc()/free() 并且没有操作系统 运行(例如裸机嵌入式系统)时,如何处理内存分配和跟踪?

应该有一个实体来跟踪哪些地址是免费的,哪些不是。那是 OS 内存管理单元。 malloc()/free() 然后将不得不调用 OS 系统调用。所以没有OS就意味着没有malloc()/free()。我的假设错了吗?

更新:

所有答案都指出 malloc/free 可以使用静态池分配(当没有 OS 可用时)或使用内核系统调用 sbrk/brk。问题是 malloc/free 如何知道下面是否有内核?

回答(见下面他的回答下"Kuba Ober"的评论):

malloc 不需要知道任何事情,因为你 link 你的项目使用的 C 库是特定于目标的:如果你为 Linux 开发,你使用 C 库Linux,与您为 OS X 或 Windows 或裸机 ARM Cortex M0 开发时不同。或者,哎呀,准系统 x86。编写 C 库的人知道如何实现它,以便它在所需的目标上工作。例如,用于 x86 的准系统 C 库将使用 EFI 和 ACPI 来查询硬件或 BIOS 未使用的可用 RAM 块的列表,然后使用它们来完成分配请求。

malloc()free() 不需要 OS 支持。它们可以(而且经常是!)在裸机系统上实现。例如,Arduino 库使用 malloc()free() 来管理字符串。

在托管实现中(即操作系统上的应用程序 运行),malloc()free() 通常会使用操作系统服务来分配新的 "hunks"内存 - 通常一次多达几兆字节 - 并且 return 那些在未使用时操作系统的大块头。较小的分配是通过将这些内存块切割成应用程序所需的大小来处理的。这允许在没有系统调用开销的情况下管理小的分配。

在非托管实现(如裸机系统)中,应用程序已经可以访问系统上存在的所有内存,并且可以根据需要分配内存块。

在较低级别:malloc() 的托管和非托管实现通常通过将每个已分配或未分配的内存块视为链表中的条目来工作。这通常是通过在每次分配开始之前立即存储一个结构来实现的,例如

struct malloc_block {
    struct malloc_block *prev, *next;
    size_t size;
    ...
    char allocation[];
};

和 return 将指向 allocation 的指针作为 malloc() 的 return 值。 realloc()free() 等函数可以通过从指向分配的指针中减去结构的大小来检索结构。

Malloc/free 函数管理内存池。这些功能一般不是操作系统服务。

那个池是如何创建的?

在大多数系统上,malloc 调用操作系统服务将页面映射到进程地址 space 以创建和扩展内存池。如果调用 malloc,但没有内存可用,大多数实现将调用系统服务来映射更多内存并扩展池。

malloc 实现需要维护数据结构,以跟踪池中的空闲内存以及已分配的内存。这是通过许多不同的方式完成的。程序员 select 最适合他们的 malloc/free 组合并将其 link 到他们的应用程序中并不少见。

所以,是的,通常涉及操作系统。

但是你问的是没有操作系统是否可以实现。

假设你做了:

   static char pool [POOLSIZE] ;

在您的 malloc 实现中。这样您就不需要系统服务来在执行期间创建池。另一方面,您的池有固定大小。

一般来说:没有,或者至少在 运行 时间没有,如果我们将 运行 时间定义为 main() 进入和返回之间的时刻。

假设您实现了在固定大小的池上运行的 malloc:

static char pool[MALLOC_POOL_SIZE];

void *malloc(size_t size) {
  …
}

void free(void *block) {
  …
}

然后,在托管和非托管实现中,您都可以进行动态内存分配。在托管实现中,二进制加载器将确保在 pool 后面映射内存。在非托管实现中,链接器将在可用 RAM 中预先定位池,如果池太大,链接将失败。

所以不,一般来说,一旦您的代码 运行ning 就不需要 OS 参与,但是需要 OS 参与才能使您的代码 运行第一名(如果有 OS)。

当然,“不需要”意味着不需要,但不排除 OS 在特定 C 运行time 库中支持动态内存分配。在大多数托管 运行 次中,malloc 使用通过调用相关 OS API 动态扩展(可能收缩)的池。在经典 Unix 上,扩展将通过 brk 系统调用完成。