接着上面的常识,这篇首要总结如下几个方面常识:
1、物理地址的页、区等概念
2、内核运用内存的函数
3、分配字节与分配页
一、区、页
前面linux下内存办理学习心得(一)也现已说了关于页的概念,在内核下面是把物理页(页框)作为分配的底子单元,内核下运用struct page结构体来表明体系中的物理页其间该结构体表明页是否被锁定在内存中,是否为脏页,该页被引证几回,一起还有页的虚拟地址等等。要害一点page结构只与物理页有关而与虚拟页无关,结构仅仅意图在于描绘物理内存自身,而不是描绘包括在其间物理页中的数据。
下面阐明一下怎样寻址到物理页:
机器语言指令中呈现的内存地址,都是逻辑地址,需求转化成线性地址,再经过MMU(CPU中的内存办理单元)转化成物理地址才干够被拜访到。
咱们写个最简略的hello world程序,用gccs编译,再反编译后会看到以下指令:
mov 0x80495b0, %eax
这儿的内存地址0x80495b0便是一个逻辑地址,有必要加上隐含的DS数据段的基地址,才干构成线性地址。也便是说0x80495b0是当前使命的DS数据段内的偏移。
在x86保护模式下,段的信息(段基线性地址、长度、权限等)即段描绘符占8个字节,段信息无法直接寄存在段寄存器中(段寄存器只要2字节)。Intel的规划是段描绘符会集寄存在GDT或LDT中,而段寄存器寄存的是段描绘符在GDT或LDT内的索引值(index)。
Linux中逻辑地址等于线性地址。为什么这么说呢?由于Linux一切的段(用户代码段、用户数据段、内核代码段、内核数据段)的线性地址都是从0x00000000开端,长度4G,这样线性地址=逻辑地址+ 0x00000000,也便是说逻辑地址等于线性地址了。
前面说了Linux中逻辑地址等于线性地址,那么线性地址怎样对应到物理地址呢?这个咱们都知道,那便是经过分页机制,详细的说,便是经过页表查找来对应物理地址。
精确的说分页是CPU供给的一种机制,Linux仅仅依据这种机制的规矩,运用它完结了内存办理。
在保护模式下,操控寄存器CR0的最高位PG位操控着分页办理机制是否收效,假如PG=1,分页机制收效,需经过页表查找才干把线性地址转化物理地址。假如PG=0,则分页机制无效,线性地址就直接做为物理地址。
分页的底子原理是把内存区分红巨细固定的若干单元,每个单元称为一页(page),每页包括4k字节的地址空间(为简化剖析,咱们不考虑扩展分页的状况)。这样每一页的开始地址都是4k字节对齐的。为了能转化成物理地址,咱们需求给CPU供给当前使命的线性地址转物理地址的查找表,即页表(page table)。留意,为了完结每个使命的平整的虚拟内存,每个使命都有自己的页目录表和页表。
为了节省页表占用的内存空间,x86将线性地址经过页目录表和页表两级查找转化成物理地址。
32位的线性地址被分红3个部分:
最高10位Directory页目录表偏移量,中心10位Table是页表偏移量,最低12位Offset是物理页内的字节偏移量。
页目录表的巨细为4k(刚好是一个页的巨细),包括1024项,每个项4字节(32位),项目里存储的内容便是页表的物理地址。假如页目录表中的页表没有分配,则物理地址填0。
页表的巨细也是4k,相同包括1024项,每个项4字节,内容为终究物理页的物理内存开始地址。
每个活动的使命,有必要要先分配给它一个页目录表,并把页目录表的物理地址存入cr3寄存器。页表能够提早分配好,也能够在用到的时分再分配。
仍是以mov0x80495b0, %eax中的地址为例剖析一下线性地址转物理地址的进程。
前面提到Linux中逻辑地址等于线性地址,那么咱们要转化的线性地址便是0x80495b0。转化的进程是由CPU主动完结的,Linux所要做的便是准备好转化所需的页目录表和页表(假定现已准备好,给页目录表和页表分配物理内存的进程很杂乱,后边再剖析)。
内核先将当前使命的页目录表的物理地址填入cr3寄存器。
线性地址0x80495b0转化成二进制后是0000 1000 0000 0100 1001 0101 1011 0000,最高10位0000 1000 00的十进制是32,CPU检查页目录表第32项,里边寄存的是页表的物理地址。线性地址中心10位00 0100 1001的十进制是73,页表的第73项存储的是终究物理页的物理开始地址。物理页基地址加上线性地址中最低12位的偏移量,CPU就找到了线性地址终究对应的物理内存单元。
咱们知道Linux中用户进程线性地址能寻址的规模是0-3G,那么是不是需求提早先把这3G虚拟内存的页表都树立好呢?一般状况下,物理内存是远远小于3G的,加上一起有许多进程都在运转,底子无法给每个进程提早树立3G的线性地址页表。Linux运用CPU的一个机制处理了这个问题。进程创立后咱们能够给页目录表的表项值都填0,CPU在查找页表时,假如表项的内容为0,则会引发一个缺页反常,进程暂停履行,Linux内核这时分能够经过一系列杂乱的算法给分配一个物理页,并把物理页的地址填入表项中,进程再康复履行。当然进程在这个进程中是被遮盖的,它自己的感觉仍是正常拜访到了物理内存。
可是页又能够有不同的运用方法,所以内核就引进区的概念,将页区分红为不同的区:
linux首要运用了四种区:
ZONE_DMA:这个区包括页能用来履行DMA操作。
ZONE_DMA32:和ZONE_DMA相似,不过只能被32位设备拜访。
ZONE_NORMAL:这个区包括的都是能正常映射的页。
ZONE_HIGHEM:包括“高端内存”。
这样linux把体系区分为区,构成不同的内存池然后用于不同的用处。留意:区的概念只不过是内核的分配,而自身物理内存是无法这样分配的。