转 Linux内存管理原理



- 虚拟内存的管理,这是介于应用程序请求与物理内存之间的一个逻辑层。
- 物理内存的管理。
- 内核虚拟内存的管理/内核内存分配器,这是一个用来满足对内存的请求的组件。这种对内存的请求可能来自于内核,也可能来自于用户。
- 虚拟地址空间的管理。
- 交换和缓存。
- 段控制单元模型,通常专用于 Linux
- 分页模型,通常专用于 Linux
- 物理内存方面的知识
- 逻辑地址 (logical address) 是存储位置的地址,它可能直接对应于一个物理位置,也可能不直接对应于一个物理位置。逻辑地址通常在请求控制器中的信息时使用。
- 线性地址 (linear address) (或称为 平面地址空间)是从 0 开始进行寻址的内存。之后的每个字节都可顺序使用下一数字来引用(0、1、2、3 等),直到内存末尾为止。这就是大部分非 Intel CPU 的寻址方式。Intel® 架构使用了分段的地址空间,其中内存被划分成 64KB 的段,有一个段寄存器总是指向当前正在寻址的段的基址。这种架构中的 32 位模式被视为平面地址空间,不过它也使用了段。
- 物理地址 (physical address) 是使用物理地址总线中的位表示的地址。物理地址可能与逻辑地址不同,内存管理单元可以将逻辑地址转换成物理地址。

- 基址 (base address) 包含某个物理内存位置的地址
- 长度值 (length value) 指定该段的长度
也也可表示成 -> 段标识符: 偏移量

- 一个 13 位的索引,用来标识 GDT 或 LDT 中包含的对应段描述符条目
- TI (Table Indicator) 标志指定段描述符是在 GDT 中还是在 LDT 中,如果该值是 0,段描述符就在 GDT 中;如果该值是 1,段描述符就在 LDT 中。
- RPL (request privilege level) 定义了在将对应的段选择器加载到段寄存器中时 CPU 的当前特权级别。

- 当所有的进程都使用相同的段寄存器值时(当它们共享相同的线性地址空间时),内存管理更为简单。
- 在大部分架构上都可以实现可移植性。某些 RISC 处理器也可通过这种受限的方式支持分段。

- 内核代码段
- 内核数据段
- 用户代码段
- 用户数据段
- TSS 段
- 默认 LDT 段
- Base = 0x00000000
- Limit = 0xffffffff (2^32 -1) = 4GB
- G(粒度标志)= 1,表示段的大小是以页为单位表示的
- S = 1,表示普通代码或数据段
- Type = 0xa,表示可以读取或执行的代码段
- DPL 值 = 0,表示内核模式
- Base = 0x00000000
- Limit = 0xffffffff
- G = 1
- S = 1
- Type = 0xa,表示可以读取和执行的代码段
- DPL = 3,表示用户模式
- Base = &tss (对应进程描述符的 TSS 字段的地址;例如 &tss_struct)这是在 Linux 内核的 schedule.h 文件中定义的
- Limit = 0xeb (TSS 段的大小是 236 字节)
- Type = 9 或 11
- DPL = 0。用户模式不能访问 TSS。G 标志被清除
- 为一个页定义的访问权限中保存了构成该页的整组线性地址的权限
- 页的大小等于页框的大小

- Directory 以 10 MSB 表示(Most Significant Bit,也就是二进制数字中值最大的位的位置 —— MSB 有时称为最左位)。
- Table 以中间的 10 位表示。
- Offset 以 12 LSB 表示。(Least Significant Bit,也就是二进制整数中给定单元值的位的位置,即确定这个数字是奇数还是偶数。LSB 有时称为最右位。这与数字权重最轻的数字类似,它是最右边位置处的数字。)

- cr3 + Page Directory (10 MSB) = 指向 table_base
- table_base + Page Table (10 中间位) = 指向 page_base
- page_base + Offset = 物理地址 (获得页框)
- 页全局目录 (Page Global Directory),即 pgd,是多级页表的抽象最高层。每一级的页表都处理不同大小的内存 —— 这个全局目录可以处理 4 MB 的区域。每项都指向一个更小目录的低级表,因此 pgd 就是一个页表目录。当代码遍历这个结构时(有些驱动程序就要这样做),就称为是在“遍历”页表。
- 页中间目录 (Page Middle Directory),即 pmd,是页表的中间层。在 x86 架构上,pmd 在硬件中并不存在,但是在内核代码中它是与 pgd 合并在一起的。
- 页表条目 (Page Table Entry),即 pte,是页表的最低层,它直接处理页(参看 PAGE_SIZE),该值包含某页的物理地址,还包含了说明该条目是否有效及相关页是否在物理内存中的位。

- 21 MSB 保留未用
- 13 LSB 由页面偏移量表示
- 其余的 30 位分为:
- 10 位用于页表
- 10 位用于页全局目录
- 10 位用于页中间目录

- 在启动时,系统为 8 MB 的物理内存设置页表。
- 然后,第二个阶段完成对其余物理地址的映射。
- ZONE_DMA(0-16 MB):包含 ISA/PCI 设备需要的低端物理内存区域中的内存范围。
- ZONE_NORMAL(16-896 MB):由内核直接映射到高端范围的物理内存的内存范围。所有的内核操作都只能使用这个内存区域来进行,因此这是对性能至关重要的区域。
- ZONE_HIGHMEM(896 MB 以及更高的内存):系统中内核不能映像到的其他可用内存。

- 对于某个用户页面的请求可以首先从“普通”区域中来满足(ZONE_NORMAL);
- 如果失败,就从 ZONE_HIGHMEM 开始尝试;
- 如果这也失败了,就从 ZONE_DMA 开始尝试。
*p = 1;
- 0xF000FF00这个地址对于x86是16bit段地址+16bit偏移地址,即,0xF000 * 16 + 0xFF00 = 0xF0000 + 0xFF00 = 0xFFF00
地址对于ARM等为采用段地址的处理器,就是空间0xF000FF00。x86处理器用实际地址做第一步跳转(软重启):typedef void (*lpFunction) ();//define a function pointer type
lpFunction lpReset = (lpFunction)0xF000FFF0; //get a pointer that point to the addr
lpRest(); //go to the function at addr- MMU
memory management unit,辅助内存管理,提供虚拟和物理地址映射、内存访问权限保护、Cache缓存控制。Kernel借助MMU让用户感觉可以使用很大的内存空间,而让开发者在写程序的时候可以不考虑物理实际容量。TLB:Translation Lookaside Buffer,转换旁路缓存。是MMU的核心部件,缓存少量的虚拟–物理关系,是转换表的Cache,也称为“快表”。TTW:Translation Table walk,转换表漫游。当TLB没有需要的转换对,通过内存中的转换表(常常是多级页表,从页表记地址寄存器找到页表,一层一层直到代码页。)访问得到虚拟–物理关系,TTW成功就写入TLB。写入之后如果权限正确将访问Cache或者内存找到相应的数据。如果不允许,MMU会向ARM发送一个存储器异常。Linux三级页表
- PGD,Page Global Directory (页目录);
- PMD,Page Middle Directory (页目录);
*前两者内部的成为PDE,页目录项,Page Directory Entry。- PTE,Page Table Entry (页表项,每一个表项对应一个物理页)。
相关宏可见下图:一般由虚拟地址三级查询得到PTE的页表的过程(page table walk):- 有描述进程占有资源的和需要访问的虚拟地址通过得到一级页表入口
- 通过得到二级页表入口
- 通过得到目标页表项
更多详细可查看reference [1]注:Linux 2.6支持不带MMU的处理器。其为了兼容嵌入式系统,融合了uClinux,来支持MMU-Less系统。2 Linux内存管理包含MMU的处理器可以使进程的访问空间达到4G,0-3G是User Space,3-4G是Kernel Space。为3G末尾,即0x86的。每个进程有自己的页表,相互独立。内核空间由内核负责映射,固定不随进程变化。而1G的Kernel Space划分为:- 物理内存映射区(0-896MB),线性映射,常规内存。当物理内存大于896MB,超出部分称为高端内存。
- 896MB之后的区域:
- vmalloc分配器区(前后有隔离带,地址VMALLOC_START ~ VMALLOC_END)
- 高端内存映射区(高端内存只能以映射在这里)(PKMAP_BASE) 更多关于 高端内存
- 专用页面映射区(实际中FIXADDR_START ~ FIXADDR_TOP)这部分需要配置。
- 保留区域(实际中FIXADDR_TOP ~ 4G区域)
当内存超过4G,需要使用CPU扩展分页(PAE)模式提供的64bit也目录项才能访问到更高物理内存,需要CPU支持。3 内存存取内存申请下面会提到的内存申请:- malloc - free: 用户空间
- kmalloc - kfree: 内核空间,物理连续
- __get_free_pages - free_pages: 内核空间,物理连续
- vmalloc - vfree: 内核空间,物理不连续,虚拟连续
- slab: kmem_cache_create - kmem_cache_destory
1 用户空间内存动态申请申请的空间在heap上,需要申请者用释放。注意尽量成对出现,避免内存泄漏。注:C Linux的malloc常用和系统调用实现。2 内核空间内存动态申请kmalloc()申请内存位于物理内存映射区,物理上也连续。和真实物理地址只有一个固定的offset。size是大小,flag是标志,GFP_KERNEL表示在内核空间进程中申请内存。其底层依赖实现。使用这个flag后,如果不能满足,进程会睡眠等待页,可能会引起阻塞。因此不能在++中断上下文,spin lock++中使用GFP_KERNEL申请内存。在++中断处理函数,tasklet,内核定时器++非进程上下文不能阻塞,应该用GFP_ATOMIC申请内存,不存在空闲会直接返回。相应其他标志位定义于:include/linux/gfp.h。释放空间。__get_free_pages()Linux Kernel最底层使用的获取空间的方法。底层以page的2^n为单位管理空闲内存,所以内存页的申请是以page为单位。指向一个清零的新page。指向新页但不清零,实际上是用了order为0的下一个函数。获取多个pages数量是2^order,不清零。order最大是10或11,硬件相关。前面三个函数的实现其实是调用了,该函数可以在用户空间,也可以在内核空间使用。返回。释放:特别注意order前后要一致。vmalloc()在虚拟空间得到一块连续区域,在vmalloc专用区,物理内存不一定连续。用于较大的顺序缓冲区分配内存,开销远大于GFP,新的页表要被建立。如果是用它申请少量内存,是不妥的。释放slab以page为单位容易产生内部碎片(internal fragmentation)。同时设想如果能让前后两次相同对象的分配在同一块内存,而且已经保留的数据结构,就能提高效率。得到slab概念,驻留任意数目,同样大小的后背缓存。创建:struct kmem_cache *kmem_cache_create(
const char *name, size_t size, //size为每个等大结构的大小byte
size_t align, unsigned long flags,
viod (*ctor)(void*, struct kmem_cache *, unsigned long),
void (*dtor)(void*, struct kmem_cache *, unsigned long));`- 分配slab缓存:
void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags);
//在之前分配的slab中分出一块并返回首指针- 释放slab缓存:
void kmem_cache_free(struct kmem_cache *cachep, void *objp);
- 回收整个slab:
int kmem_cache_destroy(struct kmem_cache *cachep);
- 可以获知slab的分配使用情况。
注意slab底层也依赖于,只是分割了小单元减少内部碎片方便管理。内存池也是用与分配大量小对象的后背缓存技术。相关函数有,,,。虚拟地址和物理地址使用实现内核虚拟向物理地址的转化,函数实现和体系结构相关。物理向虚拟。仅仅适用于常规内存区域。
reference[2] 高端内存,http://ilinuxkernel.com/?p=1013notificationsource: 《Linux设备驱动开发详解》(第二版),内容为读书笔记和网络资料,有些资料原始来源不详,分享为了方便自己和他人查阅。如有侵权请及时告知,对于带来的不便非常抱歉。转载请注明来源。Terrence Zhou.
- 可以获知slab的分配使用情况。
- 回收整个slab:
- 释放slab缓存:
- MMU
转 Linux内存管理原理的更多相关文章
- 【转帖】linux内存管理原理深入理解段式页式
linux内存管理原理深入理解段式页式 https://blog.csdn.net/h674174380/article/details/75453750 其实一直没弄明白 linux 到底是 段页式 ...
- Linux内存管理原理
本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址又叫线性地址.linux没有采用分段机制,所以逻辑地址和虚拟地址(线性地址)(在用户态,内核态逻 ...
- Linux内存管理原理【转】
转自:http://www.cnblogs.com/zhaoyl/p/3695517.html 本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址 ...
- Linux内存管理原理 与文件读写 图 相当详细
http://www.cnblogs.com/zhaoyl/p/3695517.html http://www.cnblogs.com/huxiao-tee/p/4657851.html#_label ...
- 浅谈Linux内存管理机制
经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...
- 了解linux内存管理机制(转)
今天了解了下linux内存管理机制,在这里记录下,原文在这里http://ixdba.blog.51cto.com/2895551/541355 根据自己的理解画了张图: 下面是转载的内容: 一 物理 ...
- Windows内存管理和linux内存管理
windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...
- Linux内存管理 (5)slab分配器
专题:Linux内存管理专题 关键词:slab/slub/slob.slab描述符.kmalloc.本地/共享对象缓冲池.slabs_partial/slabs_full/slabs_free.ava ...
- Linux内存管理专题
Linux的内存管理涉及到的内容非常庞杂,而且与内核的方方面面耦合在一起,想要理解透彻非常困难. 在开始学习之前进行了一些准备工作<如何展开Linux Memory Management学习?& ...
随机推荐
- POJ:3685-Matrix
Matrix Time Limit: 6000MS Memory Limit: 65536K Total Submissions: 7879 Accepted: 2374 Description Gi ...
- 笔记-python-redis接口
笔记-python-redis接口 1. python 与redis接口 redis是redis数据库的python接口包,为python提供的redis的调用接口. 注:文档内容主要基于h ...
- IAR FOR STM8S 错误 An error occurred while retrieving GDI features: gdi-error [40201]解决方法
今早使用IAR调试编译调试一个工程,发现IAR竟然出现如下错误信息 An error occurred ]: Can't access configuration database 在网上查看了一下, ...
- JsBridge "Uncaught TypeError: Cannot call method 'callHandler' of undefined", source
h5和原生结合开发app越来越流行.其实就是webview 的js调用native的方法.也就是需要搭建一个桥.这样的桥早就有人搭建好了,那就是jsbridge. git地址: https://git ...
- Android 人脸识别
Android人脸识别技术,可以参考下面的网站. http://www.faceplusplus.com.cn/ 本项目使用的就是该网站的api. 项目具体使用的技术代码 /** * 用来压缩图片的方 ...
- erlang节点局域网通信
节点1: F:\WorkSpace\Server\src>erl -name hw@192.168.10.142 -setcookie 4213 consulting .erlang in &q ...
- viewDidLoad dispatch_sync
- (void)viewDidLoad { [super viewDidLoad]; NSLog(@"1"); dispatch_sync(dispatch_get_main_qu ...
- 手把手教你写Windows 64位平台调试器
本文网页排版有些差,已上传了doc,可以下载阅读.本文中的所有代码已打包,下载地址在此. ------------------------------------------------------- ...
- (转\整)UE4游戏优化 多人大地型游戏的优化(一)游戏线程的优化
施主分享随缘,评论随心,@author:白袍小道 小道暗语: 1.因为小道这里博客目录没自己整,暂时就用随笔目录结构,所以二级目录那啥就忽略了.标题格式大致都是(原or转) 二级目录 (标题) 2.因 ...
- 波动数列 神奇的dp
问题描述 观察这个数列: 1 3 0 2 -1 1 -2 ... 这个数列中后一项总是比前一项增加2或者减少3. 栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减 ...