- 论坛徽章:
- 9
|
HI:
1.内存分配中 malloc 和 kmalloc 负责的层次不同,malloc 是 GLIB 层,属于用户空间内存分配,kmalloc 属于 Kernel 层,属于内核空间内存分配.
kmalloc 的分配只与要分配的大小有关,它根据分配的大小来选择分配器,
2. 如果 size 比较大,其从 Buddy 内存管理器里面分配内存.如果 size 不大,就从 SLUB 或者 SLAB 分配器里面分配内存.
kmalloc 分配的内存都是物理内存,这些物理内存与虚拟地址一一对应,其映射关系也是一一对应的.
3. malloc 属于用户空间的内存分配,由于它和内核之间还存在一个 GLIB 层,Glib 层有自己的内存管理.
举个例子,malloc 在用户空间分配一部分内存之后,如果不对这部分内存进行写操作的话,这段虚拟地址是不进行映射的.
4. 当用户对 malloc 分配的空间进行写操作,MMU 就会查找该虚拟地址对应的物理地址,这里就涉及查表,后面会讲.如果虚拟地址没有对应的物理地址,
那么内核就发生缺页错误,之后就会建立虚拟地址和物理地址的映射.
5. 由于使用 malloc 是从堆里面分配内存,这段内存建立映射的时候使用匿名映射.匿名映射内容很复杂,这里不做解释.
6. 回到 4 中所讲的,如果对 malloc 分配的空间进行写操作,且虚拟地址有对应的物理地址,那么内核就查表.其代码流程如下:
unsigned long addr = xxx; /* 已知的虚拟地址 */
pgd_t *pgd;
pmd_t *pmd;
pte_t *pte;
struct page *page;
unsigned long phys_addr;
pgd = pgd_offset(current->mm,addr);
pmd = pmd_offset(pgd,addr);
pte = pte_offset_map(pmd,pte);
page = pte_page(pte);
phys_addr = page_address(page);
这样就可以通过虚拟地址找到物理地址.
7. 用户空间的使用虚拟地址 0 ~ 3G,内核空间使用 3G ~ 4G 虚拟地址. kmalloc 的物理地址可要根据 GFP 标志来确认.
如果 GFP_KERNL 的话,那么是从低端物理内存分配,如果是 GFP_HIGHMEM 的话,那么从高端物理内存分配.
8. A -> fork() -> B 之后,B 进程的内存空间,即 task_struct 成员 mm. mm 属于 struct mm_struct ,这个结构负责管理进程的内存信息.
内核在使用 fork 创建新的进程时候,进程 mm_struct 对应的内核部分映射是相同的,但用户空间的映射是进程自己独占的,
也就是说对于任何进程来说,它们看到的内核空间都是相同的,但各自的 0 ~ 3G 空间,它们只能看到自己一个进程在独占这 0 ~ 3 G 的内存.
也就只有 B 进入内核态修改了 3G ~ 4G 的地址, A 程序才知道.
9. PGD 页表有 4 个页面大小,为 16K 大小,起始的虚拟地址为 swapper_pg_dir.PGD 全局页表只有物理地址对应的部分才被写值.
PGD 后 1/4 是对应内核空间,但不代表后 1/4 的 PGD 表都被有对应的 PTE 页表.后面 1/$ 的 PGD 对所有的进程来说都是相同的.
a. mem_map 负责将物理内存按 struct page 大小从低地址到高地址紧密排列在一起,形成一个数组.
对应物理页面是否使用,要通过 struct page 的 _mapcount 和 _count 两个成员来判断.
|
|