Linuxmemorymanagementi386保护模式的分段与分页Linux分页线性地址空间分布用户地址空间内核地址空间空闲物理内存管理内核物理内存分配接口共享存储Intelx86保护模式的地址映射段选择子16bits段内偏移32bits页内偏移12bits物理地址32bits页目录索引10bits页表索引10bits逻辑地址线性地址物理地址GDT、LDTpgd、pte……Intelx86的分段描述符索引13bitsGDT/LDT1bit段选择子访问特权级2bits段内偏移32bits段基地址32bits段描述符8bytes+线性地址32bits段界限20bitsGDT…………Linux在i386上的分页线性地址物理地址32bitspmd_t*dir+页帧首地址20bitsPAGE_SHIFT页内偏移12bits页目录索引10bits页表索引10bits#definePMD_SHIFT22#definePTRS_PER_PMD1#definepmd_index(address)(((address)PMD_SHIFT)&(PTRS_PER_PMD-1))pgdpte存在位读写位用户态/核心态访问位表示是否采用写透方式表示是否启用高速缓存访问位已写标志位页大小,4K(0)或4M(1),只适用于页目录表项页目录表项和页表项Linux的线性地址空间分配4G线性地址空间分为用户空间和内核空间,内核空间又分为物理内存区、虚拟内存分配区、高端页面映射区、专用页面映射区和系统保留映射区线性地址从0x00000000到0xBFFFFFFF的3G为用户和内核共同访问,0xC0000000以上的1G由内核独享,用户态无法访问因此所有进程的页目录的后四分之一均指向内核页目录的相应目录项。为减小同步的开销,内核只在处理page_fault时同步用户进程的页目录项,因此页目录项不一致的情况是有的Linux的线性地址空间分配Linux的线性地址空间分布Memorymappedregion:File-mappingSharedlibrarieskernelcode/data/stackMemorymappedregionforsharedlibrariesruntimeheap(viamalloc)programtext(.text)initializeddata(.data)uninitializeddata(.bss)stackforbidden0%espprocessVMbrk0xc0physicalmemorysameforeachprocessprocess-specificdatastructures(pagetables,taskandmmstructs)kernelVM.data.textpdemand-zerodemand-zerolibc.so.data.textLinux的用户地址空间分布例:#includestdio.hintz=0;/*进程的数据段中*/intmain(){int*a=0;/*进程的用户栈中*/intpid=getpid();if(pid=fork()){/*父进程执行这里的代码*/a=(int*)malloc(100*sizeof(int));/*父进程的堆空间,runtimedata*/z=pid;printf(“z1=%d\n”,z);}else{/*子进程执行的代码*/a=&z;*a=pid;printf(“z2=%d\n”,z);}printf(“alldone,pid=%d\n”,pid);return1;}利用/proc查看进程的用户地址空间文件映射举例#includeunistd.h#includesys/mman.h#includesys/types.h#includesys/stat.h#includefcntl.h/*mmap.c-aprogramthatusesmmaptocopyitselftostdout*/intmain(){structstatstat;inti,fd,size;char*bufp;/*openthefile&getitssize*/fd=open(./mmap.c,O_RDONLY);fstat(fd,&stat);size=stat.st_size;/*mapthefiletoanewVMarea*/bufp=mmap(0,size,PROT_READ,MAP_PRIVATE,fd,0);/*writetheVMareatostdout*/write(1,bufp,size);}用户地址空间管理-虚存段VMALinux的用户地址空间分布进程描述符中的structmm_struct*mm用来管理已分配给该进程的线性地址空间每一个连续的线性地址区间由一个vm_area_struct管理,简称vmamm中的vma按地址排序由线性链表连接起来,当vma的数量相当大的时候启用avl树,与线性链表同时管理vma以提高访问效率随着vma的动态改变,vma之间存在归并和拆分等操作分配vma并不立即分配页帧物理映射区最大为896M,如果实际物理内存不足896M,则该区与实际物理内存大小相等两个隔离区的作用是防止越界造成的致命损害Linux的内核地址空间分布物理区虚存区8~16M隔离区8K隔离区高端映射区固定映射区保留区线性地址0xC0000000Linux的物理内存映射一般情况下,对物理内存的访问可通过预映射机制方便的实现,Linux保留了128M的虚拟内存映射区,因此最多可以有1G-128M=896M的物理内存直接映射到0xC0000000开始的一段内核空间中当物理内存大于896M时,超过物理区的那部分内存称为高端内存,内核在存取高端内存时必须将它们映射到高端页面映射区,长度为4M的高端内存映射区正好占用1帧页表所表示的物理内存总量,它可以缓冲1024个高端页面的映射0X001000(4K)swapper_pg_dir核心态访问空间的页目录0X002000(8K)pg00X003000(12K)bad_pages0X004000(16K)bad_pg_table0X005000(20K)floppy_track_buffer0X006000(24K)kernel_code+textFREE0X0A0000(640KRESERVED0X100000(1M)pg_tables(4K)swap_cache_memmem_mapbitmapFREE0X000000(0K)Empty_Zero_Page由mem_init初始化初始化后的物理内存分布物理页管理(mem_map表)typedefstructpage{/*物理页描述字*/structpage*next,*prev;/*由于搜索算法的约定,这两项必须首先定义*/structinode*inode;/*若该页帧的内容是文件,则inode和offsetunsignedlongoffset;/*指出文件的inode和偏移位置*/structpage*next_hash;atomic_tcount;/*访问此页帧的进程记数,大于1表示由多个进程共享*/unsignedflags;/*atomicflags,somepossiblyupdatedasynchronously*/unsigneddirty:16,/*页帧修改标志*/age:8;/*页帧的年龄,越小越先换出*/structwait_queue*wait;structpage*prev_hash;structbuffer_head*buffers;/*若该页帧作为缓冲区,则指示地址*/unsignedlongswap_unlock_entry;unsignedlongmap_nr;/*页帧在mem_map表中的下标,page-map_nr==page-mem_map*/}mem_map_t;mem_map_t*mem_map=NULL;/*页帧描述表的首地址*/mem_map_t大小:64字节,故1M的内存需要1M/64=16K=4pages的空间存放描述字空闲物理页管理bitmap表在物理内存低端,紧跟mem_map表的bitmap表以位示图方式记录了所有物理内存的空闲状况。与mem_map一样,bitmap在系统初始化时由free_area_init()函数创建(mm/page_alloc.c)。与一般性位图不同,bitmap表分割成NR_MEM_LISTS组。buddy算法将空闲内存管理为一对对的伙伴;(2^k)页面大小伙伴算法与空闲物理页位图bitmaps:位图,标识2^k大小的内存块对(一对伙伴)的状态:0:都空闲或都忙;如果都空闲,在它们作为一块更大的空闲块出现在下一个free_area的bitmaps中。1:其中一块忙,一块空闲。内存分配的三种内核接口__get_free_pages:从buddysystem中申请大小为2^k个page的连续的物理页帧,分配内核空间的物理映射区中的一段连续的线性地址kmalloc(kfree):从slabcache中申请连续的物理内存,通常用于专用对象vmalloc(vfree):申请线性地址连续的内存空间,分配内核空间的虚拟内存映射区中的一段连续的线性地址,而实际对应的物理地址可以是不连续的,为检测越界,vmalloc的区域之间是有空洞的,且为保证效率,页面不会被swapout共享存储linux的共享存储沿用了SYSVIPC机制。进程利用共享存储进行通讯时,先向内核申请一个共享存储段。成功后把它添加(attach)到自己的地址空间,然后象使用普通存储器一样使用它。共享存储限制:一个共享存储段的大小限制:SHMMAX:4M,SHMMIN:1byte(实际是一个page大),系统中允许的共享存储段的个数限制:SHMMNI:4096。系统中允许的共享存储段占总页面数:SHMALL:2M个页面这些参数可以由超级用户修改,如:#echo2048/proc/sys/kernel/shmmni共享存储管理系统调用:shmget,shmat,shmdt,shmctlshm_server.c#includesys/types.h#includesys/ipc.h#includesys/shm.h#includestdio.h#defineSHMSZ27main(){charc;intshmid;key_tkey;char*shm,*s;key=5678;if((shmid=shmget(key,SHMSZ,IPC_CREAT|0666))0){perror(shmget);exit(1);}if((shm=shmat(shmid,NULL,0))==(char*)-1){perror(shmat);exit(1);}s=shm;for(c='a';c='z';c++)*s++=c;*s=NULL;while(*shm!='*')sleep(1);exit(0);}Example:IPCusingsharedmemoryshm_client.c/*shm-client-clientprogramtodemonstratesharedmemory.*/#includesys/types.h#includesys/ipc.h#includesys/shm.h#includestdio.h#defineSHMSZ27main(){intshmid;key_tkey;char*shm,*s;key=5678;if((shmid=shmget(key,SHMSZ,0666))0){perror(shmget);exit(1);}if((shm=shmat(shmid,NULL,0))==(char*)-1){perror(shmat);exit(1);}for(s=shm;*s!=NULL;s++)putchar(*