现在的位置: 首页 > 综合 > 正文

对操作系统的五点感受–接口/进程/内存/磁盘管理/系统架构

2013年10月23日 ⁄ 综合 ⁄ 共 4135字 ⁄ 字号 评论关闭

之一:管理和使用--对内和对外的接口
总的说来吧,任何事情都有两套机 构,一套是为使用而设置的,另一套是为管理而设置的,比如一个网站,普通的页面是为了让用户访问的,而一般还要有一系列的后台管理页面。 vm_struct的pages字段就是管理机构,而pte就是使用机构,当然管理时也可以用pte来查找,但是那样就太麻烦了,于是专门设置一个一个结 构进行vm_struct的管理。简单说,pte方式是提供给一套机制的,那就是MMU机制,MMU将不一致的用户访问集中到了一致的访问方式,那就是不 管cpu访问什么数据,什么类型的数据,都要通过MMU找到pgd的物理地址,然后按照 pmd,pte的方式找到最终页面,pte机制是被动被查找的,所有的支持mmu的操作系统都要使用这种机制,比如 linux,windows,bsd...;反过来.pages是内核主动管理vm_struct使用到的策略,不同的操作系统用到的机制不 同,linux中的方式想必很多人已经看过了,windows内核中引入了分页池和非分页池来管理内存,效果和linux一样,但是没有linux的如此 直观,简单。其实c语言的结构体不都是用来管理的吗?所以说vm_struct中的每一个字段都是用来进行管理。可以看一下一些很简单的嵌入式设备的内存 管理,它们不用结构体,直接在平坦模式的内存上分割一块自己用。
     pte方式的查找是MMU寻址用的,现代的32位CPU,很多都是有MMU的,也就是说cpu执行的时候只认虚拟地址,而pte方向的查找就是mmu用来 将虚拟地址映射到物理地址的;而.pages 的方式是内核用来管理这个vm_struct的,比如用户要释放一个addr指示的虚拟地址,内核要做的就是释放页面,而pte方式的查找只是为了mmu 而设置的,用来访问该虚拟地址的,要管理这个区域就要.pages了,用户释放addr导致的结果就是内核挨个释放.pages数组的页面,这个问题就好 比vm_area_struct中vm_next字段的管理作用一样,和vm_struct不同的是,后者是内核空间的分配,是必然要映射物理页面的,而 前者是用户空间的分配,靠缺页中断来映射页面,因此也就没有了.pages类似的和页面相关的字段。按照最小冗余的观点,.pages和pte的数据是冗 余的,指向同样的数据,那么可以去除.pages字段,然后管理vm_struct内存的时候去查pte,那么问题有二,第一,一实体身兼两职违反了 unix中每次只做好一件事的原则,违反了最小化正交原则;第二,如果用这种方式,虽然节省了一些空间,但是vm_struct的维护将和pte紧密耦 合,也就是说会变成体系结构相关的机制,这在跨平台和代码结构上也是很不好的。对内的接口用来管理,对外的接口用来使用,管理实体是确定的,因此管理的数 据结构也不用具有一般性,只要管理实体认识就可以,但是对外的接口就必须做到统一,因为使用者不统一,正好比中国和美国都期望国泰民安,很具有一般化,这 就是对外的接口,而对内的接口就是政体,不管是中央集权的还是三权分立的都可以用,很具有特殊性。
     linux内核的运行实体本质上就是在做管理工作,有了这种管理工作,上层的应用程序才可以看到一个多道程序的视图,应用程序之所以可以将一切进行,而且 那么显然,比如访存,比如IO,比如XX,并且各个应用程序不会互相冲突,原因就是内核在底层通过这些美妙的数据结构进行了管理,每一个操作系统都需要进 行这种管理,这些管理在应用程序看来是一种服务,在机器看来是一种策略,不同的操作系统按照标准必须提供相同的服务,接口本身就是机制,比如Posix或 者Win32,而实现这种接口的细节就是内核的策略了,各个不同的系统内核的策略是不同的。
之二:再谈我的child-run-first补丁的思想
我 曾经提交过一个child-run-first的内核补丁,有人认为在子进程在初始运行之前被调度到别的cpu上后也要想办法让子进程优先运行,我觉得没 有这个必要,为了减少不必要的写时复制竟然要引入那么复杂的机制实在是不应该,因为会影响到那个cpu上正在运行的进程,如果父进程和刚刚创建的子进程在 同一个cpu上竞争,那么仅仅涉及到父子竞争不会牵扯第三方,但是一旦由于负载均衡或者别的什么原因子进程在开始运行前被调度到一个不同的cpu上,那就 会牵扯到第三方,因为可能那个cpu上的当前进程刚刚开始投入运行,新的子进程如果抢占它,将对它不公平,如果不抢占它但是还是实现子进程先运行的话,那 势必会影响创建子进程的那个可怜的父亲,父亲会为了孩子而等待,这种代价太大了。实际上两个实体怎么都好办,一旦涉及第三方就会造成混乱,比如只有两个人 的情况下,一旦闻到了屁的味道,那么肯定可以定位到谁放了屁,但是如果是三个人在一起闻到了屁的味道,谁又能确定是谁放了屁呢?
之三:物理内存和虚拟内存的一一映射
linux 内核的一一线性映射关系使得内核运行十分高效,试想一下pgd的分配,cr3中的值就是pgd的物理地址,注意是物理地址,因为它是提供给MMU用 的,MMU正是用这套机制将虚拟地址对应为物理地址的,如果cr3中的是虚拟地址的话,谁来处理它呢?这是一个先有鸡先有蛋的问题,因此cr3中的是物理 地址,进一步说,在pgd分配的时候就要很快的知道pgd的物理地址,内核很善于管理页面,而页面在内存的排布也是线性的,因此内核很容易根据页面定位到 物理地址,但是内核管理数据的时候要用虚拟地址,内核也是程序,只不过具有一些特权罢了,它也是使用虚拟地址的,为了内核的高效,这就需要内核可以快速的 从物理地址定位了一个虚拟地址或者反过来,于是就有了物理地址和虚拟地址的一一映射这一说,用户一般习惯内存地址从0开始,这样的话就将前3G定为用户空 间,最后1G定位为内核空间,所有的进程共享这1G的内核空间,好像一个叉子一样,共享一个把手。内核希望使得管理效率高而采用了一一映射,这样内核很容 易从页面定位到物理地址,为了执行程序或者读写内核内存,又可以从物理地址快速定位到虚拟地址。但是为何不将用户空间的虚拟内存和物理内存也来一个一一对 应呢?不能这样,因为现代操作系统提供分时特性而支持多道程序并行,如果是一一映射,那么映射的是谁的虚拟内存呢?即使这样,用户空间的内存管理效率也不 差,linux的缺页中断非常高效
之四:windows盘符将文件树变宽,linux的树型文件系统将文件树变深
windows盘符想必 几乎每个人都明白,而linux没有盘符,其实windows虽然没有盘符它也是树形结构,拥有c,d,e,f四个盘符的系统的文件树的第一级就是一棵四 叉树,而且每棵子树的容量是不容易动态改变的,但是却可以再第一级增加新的子树从而变成5叉树直至n叉树,最后就是这棵大树越来越茂密,总之 windows的盘符限制了文件系统向深发展;linux的文件树却没有任何限制,不论纵还是深两个方向都能伸缩自如,即使你的一块磁盘只剩下一个一点空 间,你只需要建立一个空目录,然后将一块新磁盘或者分区挂在上面就可以了,很方便的,linux的文件系统的构造善于引导用户使用每一块空间,却不主张用 户将磁盘分区,linux认为分区是导致磁盘碎片化的根源,因此总是鼓励用户使用一个整磁盘工作,另外linux还善于让用户享受另一个极端,就是只将磁 盘分出最小的一部分,然后需要的时候再用fdisk挂载新的磁盘空间,毕竟linux没有什么系统目录。
之五:linux的内核和用户空间的两个世界
linux 明确区分了内核和用户空间,它们简直就是两个世界,内核启动阶段,没有任何用户空间的事情要做,而一旦内核启动完毕了,/sbin/init执行了,那么 用户空间的程序根本就不知道是刚启动完内核还是刚刚把所有进程杀掉只留下init,是的,没有办法区分它们,内核启动完毕后。/sbin/init开始接 管一切,从此系统开始了漫漫长路,init进程作为老老祖父开始开启一切用户空间的一切,包括shell,甚至加载模块...,init进程的特殊性在于 它可能是内核直接启动的,因此它是内核信任的,你可以指定任意的init进程,用init=XXX传递给内核,如果不传递,内核默认执行/sbin /init,这一点十分灵活,linux只靠一个内核和一个用户进程就能活着,内核和用户空间最小化了依赖,内核想要完全启动,需要一个init进程,而 用户空间需要内核提供系统调用接口,它们除了系统调用之外互不依赖的。用户空间哪怕再重要的事情,内核也不会负责的,内核的责任就是初始化好一个大环境, 一个稳定的大环境,一套稳定而又安全的机制,然后它就不管别的了,别的如何使用它那都是策略问题,它只是静静地在那里提高稳定底层服务,正是由于这个机制 和策略分离的特性才使得linux拥有了那么多的特性不一的发行版,你甚至可以将/目录下的目录全部删除,只保留一个vmlinuz的内核和一个 initrd,或者将必要驱动编译进内核而连initrd也不用,只要一个内核,然后放一个什么库也不用的hello kitty程序在/下,然后指定init进程为这个hello kitty进程,然后启动,不错...windows的发行版多吗?也不少?番茄花园,XX政府版...其实windows的官方发行版就是微软的版本, 别的任凭你再改,顶多改个图片和主题还能改什么?windows的启动过程决定了其内核和用户空间的紧密连续,最起码需要ntldr,另外还需要 hal.dll,还有ntoskrnl.exe等等很多模块,另外还有一些dll,注册表文件,甚至一些服务也需要在内核初始化的时候启动,这样等内核初 始化了以后,很多的服务也已经启动了,少了一点东西,命运就要面临重装系统,其实NT架构本身就是一个C/S模型的操作系统,在NT架构包括很多基于微内 核架构的操作系统中,实质上没有标准的内核文件一说的,要说操作系统就是所有的内核文件以及其依赖的库或者别的文件以及需要的服务程序,而只有在大内核系 统上才会出现明确的内核一说,大内核中,内核和用户进程才能分离的这么好。

抱歉!评论已关闭.