存储管理(二)

.8 换出与丢弃页面子

      当系统中物理内存减少时,Linux内存管理子系统必须释放物理页面。这个任务由核心交换后台进程(kswapd )来完成。 核心交换后台进程是一种特殊的核心线程。它是没有虚拟内存的进程,在物理地址空间上以核心态运行。核心交换后台进程的名字容易使人误解,其实它完成的工作比仅仅将页面交换到系统的交换文件中要多得多。其目标是保证系统中有足够的空闲页面来维持内存管理系统运行效率。  此进程由核心的init进程在系统启动时运行,被核心交换定时器周期性的调用。
      当定时器到时后,交换后台进程将检查系统中的空闲页面数是否太少。它使用两个变量:free_pages_high 和free_page_low来判断是否该释放一些页面。只要系统中的空闲页面数大于free_pages_high,核心交换后台进程不做任何工作;它将睡眠到下一次定时器到时。在检查中,核心交换后台进程将当前被写到交换文件中的页面数也计算在内,它使用nr_async_pages来记录这个数值;当有页面被排入准备写到交换文件队列中时,它将递增一次,同时当写入操作完成后递减一次。如果系统中的空闲页面数在free_pages_high甚至 free_pages_low以下时,核心交换后台进程将通过三个途径来减少系统中使用的物理页面的个数:
  减少缓冲与页面cache的大小,
  将系统V类型的内存页面交换出去,
  换出或者丢弃页面。
  如果系统中空闲页面数低于free_pages_low,核心交换后台进程将在下次运行之前释放6个页面。否则它只释放3个。以上三种方法将依次使用直到系统释放出足够的空闲页面。当核心交换后台进程试图释放物理页面时它将记录使用的最后一种方法。下一次它会首先运行上次最后成功的算法。
  当释放出足够页面后,核心交换后台进程将再次睡眠到下次定时器到时。如果导致核心交换后台进程释放页面的原因是系统中的空闲页面数小于free_pages_low,则它只睡眠平时的一半时间。一旦空闲页面数大于 free_pages_low则核心交换进程的睡眠时间又会延长。
  3.8.1 减少Page Cache和Buffer Cache的大小
  Page Cache和Buffer cache中的页面将被优先考虑释放到free_area数组中。Page Cache中包含的是内存映射文件的页面,其中有些可能是不必要的,它们浪费了系统的内存。而Buffer Cache中包含的是从物理设备中读写的缓冲数据,有些可能也是不必要的。当系统中物理页面开始耗尽时,从这些cache中丢弃页面比较简单(它不需要象从内存中交换一样,无须对物理设备进行写操作)。除了会使对物理设备及内存映射文件的访问速度降低外,页面丢弃策略没有太多的副作用。如果策略得当,则所有进程的损失相同。
  每次核心交换后台进程都会尝试去压缩这些cache。
  它首先检查mem_map页面数组中的页面块看是否有可以从物理内存中丢弃出去的。当系统中的空闲页面数降低 到一个危险水平时,核心后台交换进程频繁进行交换,则检查的页面块一般比较大。检查的方式为轮转,每次试图压缩内存映象时,核心后台交换进程总是检查不同的页面块。这是众所周知的clock算法,每次在整个mem_map页面数组中对页面进行检查。
  核心后台交换进程将检查每个页面看是否已经被page cache或者buffer cache缓冲。读者可能已经注意到共享页面不在被考虑丢弃的页面之列,这种页面不会同时出现在这两种cache中。如果页面不在这两者中任何一种之中时,它将检查mem_map页面数组中的下一个页面。
  缓存在buffer cache(或者页面中的缓冲被缓存)中的页面可以使缓冲分配和回收更加有效。内存压缩代码将 力图释放在受检页面中包含的缓冲区。
  如果页面中包含的所有缓冲区都被释放,这个页面也将被释放。如果受检页面在Linux的page cache中,则它会从page cache中删除并释放。
  如果释放出来了足够的页面,核心交换后台进程将等待到下一次被唤醒。这些被释放的页面都不是任何进程虚拟内存的一部分,这样无须更新页表。如果没有足够的缓冲页面丢弃则交换进程将试图将一些共享页面交换出去。
  3.8.2 换出系统V内存页面
  系统V共享内存是一种用来在进程之间通过共享虚拟内存来实现进程通讯的机制。进程是如何共享内存将在IPC 一章中详细讨论。现在只需要说明系统V共享内存的任何区域都可以用一个shmid_ds数据结构来表示就足够了。 此结构包含一个指向vm_area的链表指针,vm_area是为每个共享此虚拟内存区域设计的结构。它们之间通过 vm_next_shared和vm_prev_shared指针来连接。每个shmid_ds数据结构包含一个页表入口,每个入口描叙物理页面与共享虚拟页面之间的映射关系。
  核心交换后台进程同样使用clock算法来将系统V共享内存页面交换出去。
  每次运行时,它要记得哪个共享虚拟内存区域的哪个页面是最后一个被交换出去的。两个索引可以协助它完成这项工作,其一是一组shmid_ds数据结构的索引,另一个是系统V共享内存区域的页表入口链表的索引。 这能够保证对系统V共享内存区域作出公平的选择。
  由于对于给定的系统V共享虚拟内存的物理页面框号被保存在所有共享此虚拟内存区域进程的页表中,核心 交换后台进程必须同时修改所有的页表以表示页面不再在内存而在交换文件中。对于每个要交换出去的共享 页面,核心交换后台进程可以在每个共享进程的页表中的页表入口中找到它们(通过vm_area_struct数据结 构)。如果对应此系统V共享内存的页面的进程页表入口是有效的,它可以将其转变成无效,这样换出页表入口和共享页面的用户数将减一。换出系统V共享页表入口的格式中包含一个对应于一组shmid_ds数据结构的索引以及一个对系统V共享内存区域的页表入口索引。
  如果所有共享进程的页表都被修改后此页面的记数为0则共享页面可以被写到交换文件中。同样指向此系统V共享内存区域的shmid_ds数据结构链表中的页表入口也被换出页表入口代替。换出页表入口虽然无效但是它包含一组打开的交换文件的索引,同时还能找到换出页面在文件中的偏移。当页面重新被带入物理内存时,这些信息十分有用。
  3.8.3 换出和丢弃页面
  交换后台进程依次检查系统中的每个进程以确认谁最适合交换出去。
  比较好的候选者是那些可以被交换出去(有些是不可被交换出去的)并且只有一个或者几个页面在内存中的进程。只有那些包含的数据无法检索的页面才会从物理内存中交换到系统交换文件中去。
  可执行映象的许多内容都可以从映象文件中读出并且可以很容易重读出来。例如,映象中的可执行指令不能被映象本身修改,所以决不会写到交换文件中去。这些页面直接丢弃就可以。当进程再次引用它们时,只需要从可执行映象文件中读入内存即可。
  一旦确定了将要被交换出去的进程,交换后台进程将搜索其整个虚拟内存区域以找到那些没有共享或者加锁的区域。
  Linux并不会将选中的进程的整个可交换页面都交换出去,它只删除一小部分页面。
  如果内存被加锁则页面不能被交换或者丢弃。
  Linux交换算法使用页面衰老算法。每个页面有一个计数器来告诉核心交换后台进程这个页面是否值得交换出 去(此计数器包含在mem_map_t结构中)。当页面没有使用或者没有找到时将会衰老;交换后台进程仅仅交换 出那些老页面。缺省操作是:当页面被首次分配时,其年龄初始值为3,每次引用其年龄将加3,最大值为20。 每次核心交换后台进程运行它来使页面衰老-将年龄减1。这个缺省操作可以改变并且由于这个原因它们被存储在swap_control数据结构中。
  如果页面变老了(age=0),则交换后台进程将进一步来处理它。dirty页面可以被交换出去。Linux在PTE中使 用一个硬件相关位来描叙页面的这个特性(见图3.2)。然而不是所有的dirty页面都有必要写入到交换文件 中去。进程的每个虚拟内存区域可能有其自身的交换操作(由vm_area_struct结构中的vm_ops指针表示),在 交换时使用的是这些方法。否则,交换后台进程将在交换文件中分配一个页面并将页面写到设备上去。
  页面的页表入口被标志成无效但是它包含了页面在在交换文件中位置的信息,包括一个表示页面在交换文件中位置的偏移值以及使用的是哪个交换文件。但是不管使用的是哪种交换算法,以前那个物理页面将被标志成空闲并放入free_area中。Clean(或者not dirty)的页面可以丢弃同时放入free_area以备重新使用。
  如果有足够的可交换进程页面被交换出去或丢弃,则交换后台进程将再次睡眠。下次它醒来时将考虑系统中 的下一个进程。通过这种方法,交换后台进程一点一点地将每个进程的可交换或可丢弃物理页面收回知道系 统再次处于平衡状态。这比将整个进程交换出去要公平得多。
  3.9 The Swap Cache
  当将页面交换到交换文件中时,Linux总是避免页面写,除非必须这样做。当页面已经被交换出内存但是当有进程再次访问时又要将它重新调入内存。只要页面在内存中没有被写过,则交换文件中的拷贝是有效的。
  Linux使用swap cache来跟踪这些页面。这个swap cache是一个页表入口链表,每个对应于系统中的物理页面。这是一个对应于交换出页面的页表入口并且描叙页面放置在哪个交换文件中以及在交换文件中的位置。 如果swap cache入口为非0值,则表示在交换文件中的这一页没有被修改。如果此页被修改(或者写入)。 则其入口从swap cache中删除。
  当Linux需要将一个物理页面交换到交换文件时,它将检查swap cache,如果对应此页面存在有效入口,则 不必将这个页面写到交换文件中。这是因为自从上次从交换文件中将其读出来,内存中的这个页面还没有被修改。
  swap cache中的入口是已换出页面的页表入口。它们虽被标记为无效但是为Linux提供了页面在哪个交换文件中以及文件中的位置等信息。
  3.10 页面的换入
  保存在交换文件中的dirty页面可能被再次使用到,例如,当应用程序向包含在已交换出物理页面上的虚拟内存区域写入时。对不在物理内存中的虚拟内存页面的访问将引发页面错误。由于处理器不能将此虚拟地址转换成物理地址,处理器将通知操作系统。由于已被交换出去,此时描叙此页面的页表入口被标记成无效。处理器不能处理这种虚拟地址到物理地址的转换,所以它将控制传递给操作系统,同时通知操作系统页面错误的地址与原因。这些信息的格式以及处理器如何将控制传递给操作系统与具体硬件有关。
  处理器相关页面错误处理代码将定位描叙包含出错虚拟地址对应的虚拟内存区域的vm_area_struct数据结构。 它通过在此进程的vm_area_struct中查找包含出错虚拟地址的位置直到找到为止。这些代码与时间关系重大,进程的vm_area_struct数据结构特意安排成使查找操作时间更少。
  执行完这些处理器相关操作并且找到出错虚拟地址的有效内存区域后,页面错处理过程其余部分和前面类似。
  通用页面错处理代码为出错虚拟地址寻找页表入口。如果找到的页表入口是一个已换出页面,Linux必须将其 交换进入物理内存。已换出页面的页表入口的格式与处理器类型有关,但是所有的处理器将这些页面标记成无效并把定位此页面的必要信息放入页表入口中。Linux利用这些信息以便将页面交换进物理入内存。
  此时Linux知道出错虚拟内存地址并且拥有一个包含页面位置信息的页表入口。vm_area_struct数据结构可能包含将此虚拟内存区域交换到物理内存中的子程序:swapin。如果对此虚拟内存区域存在swapin则Linux会使用它。这是已换出系统V共享内存页面的处理过程-因为已换出系统V共享页面和普通的已换出页面有少许不同。如果没有swapin操作,这可能是Linux假定普通页面无须特殊处理。
  系统将分配物理页面并将已换出页面读入。关于页面在交换文件中位置信息从页表入口中取出。
  如果引起页面错误的访问不是写操作则页面被保留在swap cache中并且它的页表入口不再标记为可写。如果 页面随后被写入,则将产生另一个页面错误,这时页面被标记为dirty,同时其入口从swap cache中删除。 如果页面没有被写并且被要求重新换出,Linux可以免除这次写,因为页面已经存在于交换文件中。
  如果引起页面从交换文件中读出的操作是写操作,这个页面将被从swap cache中删除并且其页表入口被标记 成dirty且可写。

猜你喜欢

转载自yiranwuqing.iteye.com/blog/1457939
今日推荐