在硬件上,有页表给进程提供虚拟地址空间的映射。在软件上内核也用了一个数据结构来管理进程的虚拟地址空间,它就是vma。页表按照4K的粒度来控制物理映射和属性,vma的粒度也是4K,只是它的变化更加灵活。
这部分的内容对虚拟地址空间管理来说非常重要,但是呢我又发现没有太多干货可以讲。因为vma从数据结构上看 就是一个红黑树和双向链表的结合。虽然在实现细节上会有些不同,但总体结构是一致的。
那我就列出两个常用且重要的系统调用
- mmap
- munmap
这两个接口分别建立和释放了虚拟内存空间。
mmap
do_mmap
get_unmapped_area
mmap_region
vm_area_alloc
get_unmapped_area用来计算虚拟空间中空闲的地址空间,在x86上这个函数最后会由arch_get_unmapped_area来完成。并且在计算的过程中保证了起始地址和长度都是4K对齐的。
经过一系列的权限计算后,真正的映射工作由mmap_region函数来完成。这里的工作说简单就是红黑树和双向链表的操作了。
因为页表和真正的内存页是在缺页中断中填写的,所以这里仅仅是将vma的树形结构构造好,并不涉及到页表。
munmap
do_munmap
find_vma
split_vma
detach_vmas_to_be_unmapped
unmap_region
unmap_vmas
…
zap_pte_range
free_pgtables
…
free_pte_range
remove_vma_list
释放时其实需要做两件事
- 释放vma
- 释放页表和内存
别被函数的名字迷惑了,unmap_region其实释放的是页表和内存,而detach_vmas_to_be_unmapped是把vma从树形结构中释放出来。
unmap_region中又分两部,unmap_vmas释放了内存,free_pgtables释放了页表。
感觉差不多了。