MMU 虚拟地址转为物理地址的硬件 (进程内存3G超出也会页交换,到文件)
page(4K.8K内存管理基本单位) 每一个物理页一个结构 4G会占用20M 被用户空间进程/动态分配内核数据/静态内核代码/页高速缓存等引用node
flag 脏/锁 ;count引用计数,0空闲 ;*virtual 虚拟地址
RAM
分区 DDMA normal highem动态映射的页
分配:linux
alloc_pages 整个页 kmalloc 字节 连续内存虚拟地址,物理地址也连续 vmalloc 虚拟连续,物理不必定,创建页表项须要一个一个的映射 slab层,防止每一个进程本身单首创建free链,不能全局判断 高低度缓冲组。kmem_cache。每一个类型好比task_struct,inode,通用的。3个链表empty,full,parti kmem_Cache_alloc.内存紧缺/显示撤销才释放 高端内存(页并不必定永久映射,好比内核1G要访问8G物理内存,动态映射) kmap。可睡眠,永久映射 kmap_atomic 临时,原子,不睡眠,不阻塞,禁止内核抢占 cpu上数据,alloc_percpu
Linux内核高端内存的理解
前 面咱们解释了高端内存的由来。 Linux将内核地址空间划分为三部分ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM,高端内存HIGH_MEM地址空间范围为 0xF8000000 ~ 0xFFFFFFFF(896MB~1024MB)。那么如内核是如何借助128MB高端内存地址空间是如何实现访问能够全部物理内存?
当内核想访问高于896MB物理地址内存时,从0xF8000000 ~ 0xFFFFFFFF地址空间范围内找一段相应大小空闲的逻辑地址空间,借用一会。借用这段逻辑地址空间,创建映射到想访问的那段物理内存(即填充内核PTE页面表),临时用一会,用完后归还。这样别人也能够借用这段地址空间访问其余物理内存,实现了使用有限的地址空间,访问全部全部物理内存。缓存
1.不管CPU运行于用户态仍是核心态,CPU执行程序所访问的地址都是虚拟地址,MMU 必须经过读取控制寄存器CR3中的值做为当前页面目录的指针,进而根据分页内存映射机制(参看相关文档)将该虚拟地址转换为真正的物理地址才能让CPU真 正的访问到物理地址。
2.每一个进程都有其自身的页面目录PGD,Linux将该目录的指针存放在与进程对应的内存结构task_struct.(struct mm_struct)mm->pgd中。每当一个进程被调度(schedule())即将进入运行态时,Linux内核都要用该进程的PGD指针设 置CR3(switch_mm())
3.当建立一个新的进程时,都要为新进程建立一个新的页面目录PGD,并从内核的页面目录swapper_pg_dir中复制内核区间页面目录项至新建进程页面目录PGD的相应位置
4.系统调用的具体实现是将系统调用的参数依次存入寄存器ebx,ecx,edx,esi,edi(最多5个参数,该情景有两个 name和len),接着将系统调用号存入寄存器eax,而后经过中断指令“int 80”使进程A进入系统空间。因为进程的CPU运行级别小于等于为系统调用设置的陷阱门的准入级别3,因此能够畅通无阻的进入系统空间去执行为int 80设置的函数指针system_call()。因为system_call()属于内核空间,其运行级别DPL为0,CPU要将堆栈切换到内核堆栈,即 进程A的系统空间堆栈。咱们知道内核为新建进程建立task_struct结构时,共分配了两个连续的页面,即8K的大小,并将底部约1k的大小用于 task_struct(如#define alloc_task_struct() ((struct task_struct ) __get_free_pages(GFP_KERNEL,1))),而其他部份内存用于系统空间的堆栈空间,即当从用户空间转入系统空间时,堆栈指针 esp变成了(alloc_task_struct()+8192),这也是为何系统空间一般用宏定义current(参看其实现)获取当前进程的 task_struct地址的缘由。每次在进程从用户空间进入系统空间之初,系统堆栈就已经被依次压入用户堆栈SS、用户堆栈指针ESP、EFLAGS、 用户空间CS、EIP,接着system_call()将eax压入,再接着调用SAVE_ALL依次压入ES、DS、EAX、EBP、EDI、ESI、 EDX、ECX、EBX,而后调用sys_call_table+4%EAX,本情景为sys_sethostname()
5.调用copy_from_user(to,from,n),其中to指向内核空间 system_utsname.nodename,譬如0xE625A000,from指向用户空间譬如0x8010FE00。如今进程A进入了内核,在 系统空间中运行,MMU根据其PGD将虚拟地址完成到物理地址的映射,最终完成从用户空间到系统空间数据的复制app
虚拟内存交换等函数
VFS 虚拟文件系统
磁盘 分区:文件,数据,交换区域
文件系统:ext2 引导块,超级块(包含块大小等),i节点(可对应多级块3IPB,2IPB等),数据atom
崩溃恢复,元数据不一致,检查要遍历=》日志文件ext3,ext4
write()->sys_write(VFS)->ext2等的write->物理
文件,目录(目录项缓存),inode,mount point
file {链表,pathh file_operations}
目录包含文件名,inode编号。目录自身的Inode中的类型不一样,rename仅操做目录条目不动文件。
文件名到Inode有多个。硬连接指向一个Inode。软连接指向文件名spa
块IO,硬盘等,随机访问的,区别于字符设备只能顺序访问
块缓冲区,已经合成一个页缓存
块IO请求队列(一个块设备一个)
调度:linusx电梯 合并请求,临近插入线程
最终期限 超时时间(读500ms,写5s)三个队列:读FIFO/写FIFO/排序队列同linus=>超时派发队列 预测IO 超时后等几ms,相邻合并 彻底公正,每一个进程一个队列 空IO,只合并相邻的
进程地址空间 连续虚拟地址
mm_struct 分配,撤销……{内存区域vm_area_struct红黑树和链表,pgd,全部mm_struct链表,每段起始地址等}
vm_area_strict区间地址等。
虚拟地址=》物理页面 三级页表(pgd,pmd,pte)硬件效率有限,TLB缓存
在堆上分配,sbrk。改变programm break位置,进程能够访问这部分地址,若RAM未分配,内核会在进程是首次访问这些虚拟内存地址时自动分配新RAM页
malloc,free内找/分割,不够sbrk指针
页缓存(磁盘和内存ms/ns的差距)
页告诉缓存是RAM组成,对应硬盘上的物理块(扇区整数倍但比页小,通常512B/1kb/4kb),
linux 写缓存,标记脏,脏页链表, 回写进程刷会磁盘
缓存回收 LRU 双链(活跃/非活跃)
address_space 每页一个
页内搜索 基树。回收时要反向检查引用的项。根据页内偏移起终范围找vma,起点基树,终点堆,不少个共同引用优先搜索树(堆+基树)。
回写线程flusher 一个设备一个线程,每一个收集本身的。之前固定线程数,当一个设备阻塞会阻塞其上个全部线程。由于拥塞发生次数太频繁改一个设备一个线程。日志