Linux内存管理
Linux的内存划分
Linux的内存地址空间分为内核空间和用户空间,用户空间地址一般分布为0~3GB(即PAGE_OFFSET),这样剩下的3~4GB为内核空间。
x86体系结构下的内存划分
对与x86系统而言,在这1GB的内核地址空间中,又被划分为物理内存映射区、虚拟内存分配区、高端页面映射区、专用页面映射区和系统保留映射区。系统的物理内存就是被顺序映射在内核空间的物理内存映射区的,超过那部分内存地址空间的内存为高端内存,内核在存取高端内存时必须将它们映射到高端页面映射区。
在linux中内核空间各区域的表示如下:
保留区:FIXADDR_TOP ~ 4GB
专用页面映射区: FIXADDR_START ~ FIXADDR_TOP
高端页面映射区: PKMAP_BASE ~ FIXADDR_START
隔离带
虚拟内存分配器区: VMALLOC_START ~ VMALLOC_END
隔离带
常规内存区域: 16MB ~ 896MB
DMA区域: 0 ~ 16MB
当系统物理内存超过4GB时,必须使用CPU的扩展分页(PAE)模式所提供的64位页目录项才能存取到4GB以上的物理内存。其物理地址范围也扩展到36位。
ARM下的内存划分
32位arm linux的内存地址空间映射如下:
- ffff8000 ~ ffffffff : copy_user_page / clear_user_page use.
- ffff4000 ~ ffffffff: cache aliasing on ARMv6 and later CPUs.
- ffff1000 ~ ffff7fff: Reserved.
- ffff0000 ~ ffff0fff: CPU vector page.
- fffe0000 ~ fffeffff: XScale cache flush area.
- fffe8000 ~ fffeffff: DTCM mapping area for platforms with DTCM mounted inside the CPU.
- fffe0000 ~ fffe7fff: ITCM mapping area for platforms with ITCM mounted inside the CPU.
- ffc00000 ~ ffefffff: Fixmap mapping region. Addresses provided by fix_to_virt() will be located here.
- fee00000 ~ feffffff: Mapping of PCI I/O space.
- VMALLOC_START ~ VMALLOC_END-1: vmalloc() / ioremap() space.
- PAGE_OFFSET ~ high_memory-1: Kernel direct-mapped RAM region.
- PKMAP_BASE ~ PAGE_OFFSET-1: Permanent kernel mappings
- MODULES_VADDR ~ MODULES_END-1: Kernel module space
- 00001000 ~ TASK_SIZE-1: User space mappings
- 00000000 ~ 00000fff : CPU vector page / null pointer trap
内存存取
用户空间的内存动态申请
在用户空间内存的申请和释放函数分别为malloc()和free()。
对Linux而言,C库的malloc()函数一般通过brk()和mmap()两个系统调用从内核申请内存。由于在用户空间C库的malloc算法实际上具备二次管理能力,因此并不是每次申请和释放内存都一定伴随着对内核的系统调用,这可以通过mallopt函数进行配置。
另外,Linux内核总是按需调页,因此当malloc()返回时,内核并没有真正给进程分配实际的物理内存,只有当写的时候,内核才产生缺页异常,为这个页面分配实际的物理内存。
内核空间内存动态申请
内核空间内存申请所涉及的函数主要包括kmalloc()、__get_free_pages()和vmalloc()等。kmalloc()和__get_free_pages()申请的内存位于DMA和常规区域的映射区,其在物理上时连续的,并且与真实的物理地址之间只有一个固定的偏移,因此存在简单的转换关系。vmalloc()申请的内存只在虚拟内存地址空间上连续,但在实际的物理地址上却并不一定连续,由于分页机制页面映射的随机性,因此vmalloc()申请的内存地址与实际物理地址之间不存在直接的映射关系。
kmalloc()
1
2void *kmalloc(size_t size, int flags)
第一个参数是要分配的块大小;第二个参数是分配标志,用于控制kmalloc的行为,具体可参考linux/slab.h
__get_free_pages()
这一系列的函数或宏是linux内核底层用于获取空闲内存的方法因为底层的buddy算法以$2^n$页为单位管理空闲内存,所以最底层的内存申请总是以$2^n$页为单位。了解更多可参考linux/gfp.h
vmalloc()
vmalloc只为存在于软件中的较大的顺序缓冲区分配内存,其开销远远大于kmalloc和__get_free_pages。由于vmalloc的内部实现使用了GFP_KERNEL标志的kmalloc,因此不能用于原子上下文中。
slab与内存池
由于完全以也为单位申请和释放内存容易导致内存浪费,且在实际的操作系统中,存在大量对象的重复生成、使用和释放,如inode、task_struct等对象。为了解决如上问题,slab算法应运而生。
slab是建立在buddy算法之上的,它从buddy算法拿到$2^n$页面后再次进行二次管理,使得对象在前后两次被使用时分配在同一块内存或同一类内存空间且保留基本的数据结构,从而大大提高内存申请与释放的效率,因此slab实际上是一种缓存技术。在系统中可通过/proc/slabinfo货值slab的分配和使用情况。
与slab之相对应的另一种换成技术时内存池,具体可参考linux/mempool.h
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 yxhlfx@163.com
文章标题:Linux内存管理
本文作者:红尘追风
发布时间:2016-04-14, 17:26:46
原始链接:http://www.micernel.com/2016/04/14/Linux%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。