Linux 内存管理
- 内存布局
- 地址转换和MMU
- 内存分配机制(页、slab、kmalloc)
- I/O内存访问
- 内核内存到用户空间的映射mmap
- Linux缓存
- 设备资源管理框架
内存布局
- 分为内核空间和用户空间
- 二者的分割取决于CONFIG_PAGE_OFFSET(典型值,arm:0x80000000 x86:0xC0000000(3/1分割))
- 布局状态(内核占高1G)
- 内核与每个进程都共享地址空间,以便于进行系统调用避免内存换入换出的开销,从而提高系统调用的效率
- 内存组织的单元:页(取决于PAGE_SIZE,一般是4KB)。(注意与帧区分,帧:一段固定长度的连续物理内存,号码PFN,页和帧的映射page_to_pfn和pfn_to_page实现,和页的大小一样都是4KB)
内核空间寻址
- 低端内存和高端内存:低端内存(第一个896MB)高端内存(顶部128MB)
- 低端内存(线性映射):内核永久映射该896MB空间,占用物理内存的头一个896M,第一个16MB一般用于DMA。
- 高端内存(动态映射):内核地址空间顶部的128M,可临时映射1G以上的物理内存
- Tips:说人话就是,896M之内,低端内存,896M之外,高端内存。低端内存是线性映射,减去offset即可得到pa,所以很快。而高端内存的128M需要经过MMU动态映射,更慢一些。
- 访问宏:
ZONE_DMA (0-16M)
ZONE_NORMAL (16M - 896M)
ZONE_HIGHMEM (896M - 1024M)
用户空间寻址
- 描述进程的方式:struct task_struct,里面套娃一个内存映射表,大概长下面这样:
内核里表示当前进程的全局变量current->mm字段保存的就是task_struct里的mm成员,具体套娃关系如下图:
- VMA:上面一个个框实际对应的是一个又一个虚拟内存区域(VMA),每个VMA都有不同功能,且具备起始地址、长度、访问权限等属性,并且大小总是PAGE_SIZE的整数倍。
- VMA从虚拟地址角度来说是连续的,但是实际上对应的物理地址空间不一定是连续的。通过/proc//maps可查看某进程对应的VMA
内存分配机制
- 内存分配器概览
- 页面分配器:主分配器,分配单位是页,所有分配器的基础。采用伙伴算法分配页面块,块的大小是2的n次幂(1页、2页、4 页、8页、16页等)
- struct page *alloc_pages
- (gfp_t mask, unsigned int order)
- __free_pages
- (struct page *page, unsigned int order)
- struct page *alloc_pages