首页 > 开发 > 综合 > 正文

读核日记 ( 七 )

2024-07-21 02:38:23
字体:
来源:转载
供稿:网友

  作者: sunmoon
  
  内存治理是一个操作系统必不可少.并且.非常重要的一环.linux的成功.和它优秀的内存治理联系
  非常密切.因为一个系统的高效性欲稳定性往往决定于它的内存治理机制.我项很多人吃过dos下
  640k 的苦吧.
  
  前面我们介绍了386保护模式.从今天起我们将在此基础上,分析linux的虚拟存储治理,对每个程序
  员来说.他们都希望有无穷大的快速的内存,然而,现阶段是不可能的,况且,无穷大与快速本身就可
  能矛盾
  
  为了解决无穷大.linux 引入了虚拟存储系统,为了解决快速,linux 引入了cache ,交换机制等等,
  以使的存储系统,在容量上接近硬盘,速度上接近cache.(当然,我认为这是存储系统的实际目的).
  
  Linux 的内存治理采取的是分页机制.它的设计目的是分时多任务.linux 可同时处理256个任务
  (这应该与某个变量来定义,一时想不起来).同时它采用了两级饱和机制来分别内核进程与用户进程.
  
  在386 保护模式的0-4G 的线性虚拟地址中,3-4G 是留给内核进程的.而0-3G分给用户进程.内核在
  内核空间的寻址不同于用户进程在用户空间的寻址.因为内核是在启动时装入内存的.说以它可以
  直接吧地址映射到3G 以上.用户若想访问内核就不许通过swapper_pg_div 中的指针来得到页表.
  
  相反,用户进程,在用户空间的寻址是通过所用户页目录中的指针得到用户的页表.并通过页表的指
  针直接指向相应的物理内存.
  
  Linux虚拟内存的实现,需要几种不同的机制来实现:
  
  地址映射机制
  
  内存的分配与回收
  
  请页机制
  
  交换机制
  
  内存共享机制
  
  在具体的读源码之前.我们先根据我们以前学过的操作系统知识.和C语言等知识.来考虑一下,这几
  个机制如何实现.现自己设计一下.在看别人是怎样实现的.找到自己想不到.或者对效率空间有损
  的地方.这样才有进步.我不止一次的说.操作系统的某一部分,就起实现来说,非常简单.它的难点
  是如何将大量的功能集成出一个kernerl.
  
  地址映射机制,说白了,就是在虚拟内存与物理内存上的一个桥梁.它要做的事情可能就是通过几个
  不同的表.把虚拟地址转换成物理地址,把物理地址转化虚拟地址.
  
  我们以前说过.因为有系统与用户之分,它必须也要有不同的数据结构.为了解决速度等问题.它会
  有一个硬件的缓冲区
  
  对于它的数据结构.我们可以先想一下.如虚拟地址的信息,虚拟地址在那个区域等等
  
  至于请页机制,更好理解.因为linux是页式存储的.因此必然会存在空白页和使用页.既然是页.就
  必然会存在页溢出.页无效(是不是在win98 下经常出现类似错误,当然linux的内存治理不可能和
  windows一样,可基本道理相同).因此.在每一个页出错.或者该页存不下多余的数据时.就要要求内
  核分配新的页面
  
  同时.当时用fork() 产生一个新的进程时.也需要分配新的叶面.这一部分大概讲的就是进程如何
  向内和描述自己需要怎么样的和多少页
  
  在我们学习<<数据结构>>是我们学了,很多内存分配方式,如首次拟和.最佳拟和,最差拟和等等.但
  是我们可以想象.linux 大概不会用他们.那就一定是伙伴系统了.因此我们可以对于伙伴系统的分
  配,回收的基本算法.回想一下.这样在读者一部分源码时,回有意象不到的收获.
  
  至于交换机制.我们也可以现想一想.内存中总与很多使用者的页.假如这些也已经把所有的页都用
  完了.再分配时必须把其中的某些页释放.释放那些页,需要考虑.如最近不用页.近期少用页,等等
  都可以在考虑之中.
  
  这个算法,大概就是计算内存中使用的页,什么时候可以换处.说白了就是为所有的使用页计算一
  个”权”,而这个”权”就决定了他什么时候被释放以换如它的内容.需要想的是对于经常使用的页.可
  以把它放入cahe.(尽管这一部分对程序员是透明的,但我们应该理解他的原理).
  
  最后的一部分共享内存,我想和我门初学linux编程时,进程通讯里面的共享内存没有区别.大概也
  就是在它的数据结构中加入可以答应不同进程访问的tag 就行了.
  
  以上,只是我们对linux的内存治理机制的猜测,需要我们做的工作就是具体的读源码.更正不正确
  的猜想.同时学习别人的实际思路.
  
  
  
  地址的映射机制
  
  地址的映射机制,主要完成主存.辅存.和虚存之间的关联.包括磁盘文件到虚存的映射和虚存与内
  存的映射关系.为了虚拟存储和进程调度相一致.linux 采用可一系列的数据结构,和一个硬件缓存
  (TLB)来实现地址映射机制.
  
  mm_strut 用来描述进程的缓存.
  
  strUCt mm_struct
  
  {
  
  struct vm_area_struct * mmap;
/* list of VMAs */
  
  struct vm_area_struct * mmap_avl; /* tree of VMAs */
  
  struct vm_area_struct * mmap_cache; /* last find_vma result */
  
  pgd_t * pgd;
  
  atomic_t count;
  
  int map_count; /* number of VMAs */
  
  struct semaphore mmap_sem;
  
  spinlock_t page_table_lock;
  
  unsigned long context;
  
  unsigned long start_code, end_code, start_data, end_data;
  
  unsigned long start_brk, brk, start_stack;
  
  unsigned long arg_start, arg_end, env_start, env_end;
  
  unsigned long rss, total_vm, locked_vm;
  
  unsigned long def_flags;
  
  unsigned long cpu_vm_mask;
  
  unsigned long swap_cnt; /* number of pages to swap on next pass */
  
  unsigned long swap_address;
  
  /*
  
  * This is an architecture-specific pointer: the portable
  
  * part of Linux does not know about any segments.
  
  */
  
  void * segments;
  
  };
  
  他描述了一个进程的页目录,有关进程的上下文信息.以及数据.代码.堆栈的启示结束地址.还有虚
  拟存储取得数目.以及调度存储用的链表指针.他的参差比较高
  
  较高层次的vm_area-struct 是描述进程的虚拟地址区域.他形成一个算相链表.按虚地址下降排列
  .这样当内核需要在一个给定进程页上执行给定操作时.客从双向列表中找到该项.在世想有关页的
  处理.如.页错误.页换出等等
  
  他的具体结构如下:
  
  struct vm_area_struct {
  
  struct mm_struct * vm_mm; /* VM area parameters */
  
  unsigned long vm_start;
  
  unsigned long vm_end;
  
   
  
  /* linked list of VM areas per task, sorted by address */
  
  struct vm_area_struct *vm_next;
  
   
  
  pgPRot_t vm_page_prot;
  
  unsigned short vm_flags;
  
   
  
  /* AVL tree of VM areas per task, sorted by address */
  
  short vm_avl_height;
  
  struct vm_area_struct * vm_avl_left;
  
  struct vm_area_struct * vm_avl_right;
  
   
  
  /* For areas with inode, the list inode->i_mmap, for shm areas,
  
  * the list of attaches, otherwise unused.
  
  */
  
  struct vm_area_struct *vm_next_share;
  
  struct vm_area_struct **vm_pprev_share;
  
   
  
  struct vm_Operations_struct * vm_ops;
  
  unsigned long vm_offset;
  
  struct file * vm_file;
  
  unsigned long vm_pte; /* shared mem */
  
  };
  
  而page 结构 则是对物理页进行描述的一个数据结构,他不是一个真正的物理页.而只不过是描述
  了一个物理页的内容和框架.作了逻辑页的一个标志;.他的标志域定义了这个页在进行的操作.链
  域则定义了一个双项链表.时的页框.可以很轻易的查找到.为实际物理内存的使用直到方便
  
  他的具体结构如下
  
  typedef struct page {
  
  /* these must be first (free area handling) */
  
  struct page *next;
  
  struct page *prev;
  
  struct inode *inode;
  
  unsigned long offset;
  
  struct page *next_hash;

  
  atomic_t count;
  
  unsigned long flags; /* atomic flags, some possibly updated asynchronously */
  
  wait_queue_head_t wait;
  
  struct page **pprev_hash;
  
  struct buffer_head * buffers;
  
  int owner; /* temporary debugging check */
  
  } mem_map_t;
  
  所有的page 结构将都被转入一个叫做mem_map 的数组中.
  
  当一个进程运行时,他的代码段和数据段将都会被调入内存.假如它使用了共享库.共享客的内容也
  将贝雕如内存.进程运行时.系统首先分配一

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表