从多个维度来了解计算机的内存管理方式,解决以下问题:
1、内存管理硬件布局
2、为什么要有cache
3、虚拟地址和物理地址是什么
4、cpu加载内存数据过程简述
5、TLB和页表是怎么存储数据
6、cache是如何管理数据
7、查看linux上的这些信息
1、硬件布局
mmu内存管理单元,负责处理cpu的内存访问的计算机硬件。
tlb是mmu的一部分,实质是cache,用于缓存最近使用的数据的页表项。
(虚拟地址到物理地址的映射)
image.png
2、为什么要有cache
cache存储最近使用过的数据,而且一级和二级cache的速度和cpu几乎接近。如果没有cache,cpu会浪费大量的时间等待。
以下是cpu、cache、ram的访问速度。
image.png
3、虚拟地址和物理地址
对于32位字长的处理器,一个进程具有的虚拟地址空间是4GB,分为3GB的用户空间和1GB的内核空间。
所有进程的虚拟空间,映射到一块物理内存。
mmu的tlb和每个进程的页表,存储的就是这个进程的虚拟地址和物理地址的映射关系。
4、cpu加载内存数据过程简述
简单来说,cpu给mmu一个虚拟地址,mmu通过查找tlb(在mmu的cache中)/ttb(页表,在内存中),返回一个物理地址,cpu通过总线用物理地址访问内存的一个过程。
中间涉及到tlb、ttb如何存储映射、地址是如何描述的,发生缺页,错误的地址如何处理等等。
步骤:
1. MMU首先在TLB(保存虚拟地址和物理地址的映射关系)搜索。
a. 命中,则获得物理地址
b. 未命中,则在页面表中搜索
i. 命中,且有效位为1,则写入TLB,重复步骤1。
ii. 命中,且有效位为0,则触发页面交换(这是另一个过程了,简单来说,就是将数据从磁盘换入,更新页表和tlb),重复步骤1
iii. 未命中,报段错误,直接退出进程。
2. 获取物理地址后,访问cache
a. 命中,ok
b. 未命中,则访问内存,并更新至cache。
5、TLB和页表是怎么存储数据
5.1 TLB存储数据
TLB的组织有多种方式,有全相连、直接匹配、和组相连。
现在处理器都使用组相连的方式,下图所示就是,TLB有16个组,一组有4个条目。
那么取VPN(虚拟地址)的低4位,作为组索引,高2位作为标记,用于区分映射到同一个组的不同VPN.
image.png
简单描述下另外两种组织方式:
全相连---TLB的表项和线性地址没有任何关联,优点是利率用大,确定是每次搜索都要全部遍历一次。
直接匹配---线性地址通过模运算得到唯一的TLB表项,优点是降低延迟,缺点是冲突大。
那么问题来了,既然TLB存储在MMU,也就是同一个cpu core的所有进程共享这个TLB,那么如何区分多个进程的相同虚拟地址呢?
解决办法:在进程切换时,将整个TLB无效掉,但是会导致性能损失。所以,有一种更好的办法,也是现在使用的,区分不同进程的表项,具体就是:每个进程有一个ID值(x86 叫做 PCID, arm叫做ASID), linux kernel将这个ID存储在task_struct,查找TLB时,可以对比tag和ID值是否都相等,相等则命中。
为什么不能用进程ID来表示ASID呢?因为大小限制了,一般ASID是8bit或者是16bit,只能区分256/65536个进程,当ASID用完时,flush掉整个TLB。
再有个疑问,进程的内核空间和用户空间是分开的,但是内核空间是所有进程共享的,当进行TLB hit内核的时候,因为有ASID,会导致进程的TLB不能共享,如何解决?
办法就是在TLB再加一个位,表示所有进程共享。
5.2 页表存储数据
OS为每个进程维护一个独立的页表,常驻内存。页表保存此进程的虚拟地址和物理地址的映射关系。
每个CPU有一个控制寄存器,叫做页表基址寄存器PTBR(page table base register)(在处理器core i7叫做CR3),指向当前页表(页表在内存中),当进程发生切换时,寄存器的内容也更新,当然指向页表的PTBR也更新。
页表就是一个数组,虚拟地址的每个页,对应一个PTE。
每个PTE由一个有效位和一个n位地址组成,有效位为1表示该虚拟页缓存在了内存中,为0表示还未缓存到内存中,地址就指向磁盘。
image.png
为了加快命中速度,设计成多级页表,如下图,设计成4级页表。
image.png
前3级每个页表条目的定义如下:
其中,base addr,保存后一级页表的地址
image.png
第4级每个页表条目的定义如下:
其中,base addr,保存物理地址的最高40位
image.png
6、cache是如何管理数据
要知道,拿到物理地址后,会先去cache上看下有没有缓存,那么cache是如何管理地址和数据的呢?
cache也是分级的,每个cpu core有独立的一级cache(32KB),所有core共享二级(256KB)和三级cache(20480KB).
下图所示,一级cache也是分组的,分为64组,每组8行。那么物理地址的低6位作为块偏移,接下来的6位作为组索引。
通过组索引,可以知道所在的组,然后搜寻组内的每一行,对比CT标记位,命中则选择这一行。最后用b位块偏移,获取内容。
这里有一个重要思想:组中的任何一行都可以包含任何映射到这个组的存储块,所以,必须搜寻cache组中的每一行。
7、查看linux上的这些信息
image.pngimage.png
coherency_line_size: cache block大小
number_of_sets:多少个组
ways_of_associativity:几路组相连
上述表示,cache 大小为32k,将cache块,每块64字节,一共有256块。
再将256块分组,每组8行,64组。
网友评论