OS 开发中的内存管理
Memory management in OS development
我不确定这个问题是否切合主题(如果不是,我深表歉意),但我想知道在创建操作系统时如何完成内存管理。我的理解是:
- OS提供内存管理。
- 任何编程语言(高于汇编语言,例如 C)都需要已经托管的内存(用于栈帧和堆分配)。
这听起来很矛盾。如果编写内存管理器的工具首先需要内存管理器,那么如何编写内存管理器?必须在汇编中完成吗?
C 不需要托管内存。您可能正在考虑 malloc
库函数,但这只是一个函数(尽管已标准化以供 user 程序使用)。
一个易于实现的内存分配方案如下:
char * free_space;
void * kmalloc(size_t s) {
char * block = free_space;
free_space += s;
return block;
}
// free not possible
指针free_space
必须在初始化期间设置为已知空闲内存区域的开始。这可能是由引导加载程序通过多重引导信息给出的。
我很久以前写的 this code for a kernel 中可以找到更复杂的示例。
一般内存管理分为多个阶段:
在初始化过程中,像上面这样的简单方案有助于设置更复杂的分配器,就像我写的那样。
这个分配器只提供固定大小的块(通常是 4Kb,有时也是这个大小的倍数)。
当内存池被填满时,这些块是从更高级别的分配器请求的。该分配器是您通常通过 malloc
调用的分配器。一个突出的例子是 Doug Lea 的 dlmalloc。
关于堆栈:编译后的代码对堆栈指针进行递增和递减。但是很明显之前得设置成一些可用的space。对于内核,在初始化期间,您通常将其设置在您知道可用内存的某个位置,例如二进制文件的一部分。这是在汇编中完成的:
lea esp, kstack
; ...
call startup_kernel
; ...
[SECTION .bss]
resb 32768
kstack:
Startup code in assembly from the aforementioned kernel
对于稍后的进程,您使用内核分配器分配一个或更多帧,并将堆栈设置为指向它的末尾(在递减堆栈的情况下)。 another kernel 中的这个示例显示了为新进程设置堆栈所做的工作(这在很大程度上取决于实际的内核/任务切换代码)。 (在这种情况下,没有动态分配的内存,因为它是在嵌入式场景中使用的)。
操作系统需要为自身(内核)和用户管理内存。
你好像问的是用户内存管理。这是通过管理分配给进程的页面来完成的。堆栈由分配页面进程管理。
堆内存管理(如 malloc)分两部分完成。内核为操作系统提供系统服务,将页面映射到进程。其次,库管理在这些页面中创建的一个或多个内存池。
我不确定这个问题是否切合主题(如果不是,我深表歉意),但我想知道在创建操作系统时如何完成内存管理。我的理解是:
- OS提供内存管理。
- 任何编程语言(高于汇编语言,例如 C)都需要已经托管的内存(用于栈帧和堆分配)。
这听起来很矛盾。如果编写内存管理器的工具首先需要内存管理器,那么如何编写内存管理器?必须在汇编中完成吗?
C 不需要托管内存。您可能正在考虑 malloc
库函数,但这只是一个函数(尽管已标准化以供 user 程序使用)。
一个易于实现的内存分配方案如下:
char * free_space;
void * kmalloc(size_t s) {
char * block = free_space;
free_space += s;
return block;
}
// free not possible
指针free_space
必须在初始化期间设置为已知空闲内存区域的开始。这可能是由引导加载程序通过多重引导信息给出的。
我很久以前写的 this code for a kernel 中可以找到更复杂的示例。
一般内存管理分为多个阶段:
在初始化过程中,像上面这样的简单方案有助于设置更复杂的分配器,就像我写的那样。
这个分配器只提供固定大小的块(通常是 4Kb,有时也是这个大小的倍数)。
当内存池被填满时,这些块是从更高级别的分配器请求的。该分配器是您通常通过 malloc
调用的分配器。一个突出的例子是 Doug Lea 的 dlmalloc。
关于堆栈:编译后的代码对堆栈指针进行递增和递减。但是很明显之前得设置成一些可用的space。对于内核,在初始化期间,您通常将其设置在您知道可用内存的某个位置,例如二进制文件的一部分。这是在汇编中完成的:
lea esp, kstack
; ...
call startup_kernel
; ...
[SECTION .bss]
resb 32768
kstack:
Startup code in assembly from the aforementioned kernel
对于稍后的进程,您使用内核分配器分配一个或更多帧,并将堆栈设置为指向它的末尾(在递减堆栈的情况下)。 another kernel 中的这个示例显示了为新进程设置堆栈所做的工作(这在很大程度上取决于实际的内核/任务切换代码)。 (在这种情况下,没有动态分配的内存,因为它是在嵌入式场景中使用的)。
操作系统需要为自身(内核)和用户管理内存。
你好像问的是用户内存管理。这是通过管理分配给进程的页面来完成的。堆栈由分配页面进程管理。
堆内存管理(如 malloc)分两部分完成。内核为操作系统提供系统服务,将页面映射到进程。其次,库管理在这些页面中创建的一个或多个内存池。