前言
之前文章中物理ram中的最小单位一直用页来表示
这次又描述的详细了点
物理ram的最小单位 有的地方叫 块,框,页帧 在虚拟空间中最小单位也叫页 需要好好区分
不过后来想想管你虚拟页还是物理ram页 都存在物理ram上 都能想成一 一对应的关系 所以大家都叫页好像也行
内存分配接口
linux内核中有很多分配内存的接口傻傻分不清 下面总结一下每个的作用
用户空间使用(malloc/calloc/realloc/free)
用户空间(malloc/calloc/realloc/free) 。不保证物理连续。大小限制(堆申请)。单位为字节。
场景: calloc初始化为0,realloc改变内存 大小。
mmap/munmap。场景:将文件利用虚拟内存技术映射到用户空间内存当中。
brk/sbrk。场景:虚拟内存到内存的映射。
内核空间(vmalloc/vfree)
内核空间(vmalloc/vfree) 。虚拟连续/物理不连续。大小限制(vmalloc区) 单位为页(vmalloc区域)。
场景:可能睡眠,不能从中断上下文中调用,或其他不允许阻塞情况下调用。
void *vmalloc(unsigned long size);
分配不连续的物理页并且把物理页映射到连续的虚拟地址空间;
void vfree (const void * addr);
释放vmalloc分配的物理页和虚拟地址空间; .
void *vmap(struct type **pages,unsigned int count,unsigned long flags,pgprot t prot);
把已经分配的不连续物理而映射到连续的虚拟地址空间;
void vunmap(const void *addr);
释放使用vmap分配的虚拟地址空间。
slab分配器常用(kmalloc/kcalloc/krealloc/kfree) 。物理连续。大小限制(64b–4mb) 。单位为2^order字节(Normal区域)。
场景:大小有限,不如vmalloc/malloc大。
还有一个叫做kmem_ cache_ create (物理连续。64-4mb。 字节大小需要对齐(Normal区域)。
场景:便于固定大小数据的频繁分配和释放,分配时从缓存池中获取地址,释放时也不一定真正释放内存,通过slab进行管理)。
伙伴系统( get_free_ page | _ get_ free_ pages)。 物理连续。4mb (1024页) ,单位为页(Normal区域)。
场景:get free_ pages,但是限定不能使用HIGHMEM)
alloc_ page/alloc_ pages/free_ pages, 物理连续。4mb,单位为页(Normal/Vmalloc都可以) 。
场景:配置定义最大页面数2^11, -次能分配到的最大页面数是1024。
页表
页表作用把虚拟页映射到物理页
虚拟地址
在LINUX系统下,虚拟地址空间实际上是一个 mm_struct的结构体,是对一块内存空间的描述,通过这个描述向进程虚拟出一个连续的,完整的内存空间。
为什么要虚拟地址
为了让进程不直接访问物理内存
如过进程直接访问物理内存:
1.进程中的代码数据使用的是连续的地址空间,如果直接使用连续的物理内存会造成内存浪费。
2.在物理内存上任何区域和位置都能可读可写 直接访问物理内存会因为缺乏内存访问控制而导致进程的不安全
虚拟内存物理ram内存映射图
每个进程都有自己的页表数据都在物理内存上
Cpu在执行对应的进程时候都会访问相对的内存 cpu不会直接访问物理内存
而是通过虚拟地址空间 间接访问物理地址 ,操作系统给每个进程分配的逻辑地址(cpu使用的地址)
比如在32位机器上 虚拟地址空间就是0~4G 操作系统把虚拟地址空间和物理地址空间建立映射
让cpu间接访问物理地址 通常在虚拟地址空间中 512字节到8k为一个单位称为页
CPU并不是直接访问物理内存地址,而是通过虚拟地址空间来间接的访问物理内存地址。
虚拟地址空间是操作系统为每个正在执行的进程分配一个逻辑地址,比如在32位系统,范围0~4G-1。
操作系统通过将虚拟地址空间和物理内存地址之间建立映射关系,让CPU能够间接访问物理内存地址。
一般情况将虚拟地址空间以512byte-8K, 作为-个单位,称为页,并从0开始依次对它进行页编号。
这个大小就称为页面。将物理地址按照同样大小,作为一个单位,称为框或者是块。
也从0开始依次进行对每个框编号。操作系统通过维护一张表,这张表记录每一对页和框的映射关系。windows系统页面大小为4KB。
系统为每个进程建立一个页表,在进程逻辑地址空间中每一页,依次在页表中有一个表项,
记录该页对应的物理块号。
通过查找页表就可以很容易地找到该页在内存中的位置。页表具有逻辑地址到物理地址映射作用。
ARM64处理器页表
Linux内核把页表直接分为4级:
页全局目录(PGD)、
页上层目录(PUD) 、
页中间目录(PMD)、
直接页表(PT)。
如果选择三级(页全局目录、页中间目录、直接页表)。
如果选择二_级(页全局目录和直接页表)。
五级页表的结构,每个进程有独立的页表,进程的mm_struct实例成员pgd指向页全局目录。
前面四级页表的表项存放下一-级页表的起始地址,直接页表的表项存放页帧号(PFN)
查询页表,把虚拟地址转换成物理地址流程:
1、根据页全局目录的起始地址和页全局目录索弓|得到页全局目录表项的地址,然后再从表项得到页四级目录的起
始地址;
2、根据页四级目录的起始地址和页四级目录索引|得到页四级目录表项的地址,然后从表项得到页上层目录的起始
地址;
3、根据页上层目录的起始地址和页上层目录索引|得到页上层目录表项的地址,然后从表项得到页中间目录的起始
地址;
4、根据页中间目录的起始地址和页中间目录索引|得到页中间目录表项的地址,然后从表项得到直接页表的起始地
址;
5、根据直接页表的起始地址和直接页表索弓|得到页表项的地址,然后从表项得到页帧号;
6、把页帧号和页内偏移组合形成物理地址。
虚拟地址和物理地址如何对应
比如虚拟地址的宽度是48位,页长度和转换表级数关系:
页长度是4KB:使用4级转换表,转换表和内核的页表对应关系。
0级转换表对应面全局目录,1级转换表对应页_上层目录,2级转换表对应页中间目录, 3级转换表对应直接页表。