Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1281340
  • 博文数量: 168
  • 博客积分: 3483
  • 博客等级: 中校
  • 技术积分: 1696
  • 用 户 组: 普通用户
  • 注册时间: 2006-02-06 13:17
文章分类

全部博文(168)

文章存档

2015年(6)

2014年(9)

2013年(47)

2012年(11)

2011年(13)

2010年(18)

2009年(11)

2008年(42)

2007年(11)

分类: LINUX

2013-04-28 13:16:29

http://fred-zone.blogspot.com/2009/03/linux-kernel.html

Linux Kernel 記憶體管理機制之美

Linux Kernel 的穩定,有一部份可以歸功於它優良的記憶體管理機制,而探討該機制,有助於瞭解記憶體是如何被 Kernel 所使用,對開發 Linux Driver 的人來說,日後更有許多益處。最重要的是,Linux Kernel 之美是由此開始,優美的設計相當令人著迷。

Linux Kernel 的記憶體管理機制,主要由兩大部份組成:

  • Buddy System
  • Slab Allocator
Buddy System(buddy allocator)

如 一般的 Operating System Design,Linux Kernel 一樣是以 Page 為記憶體管理的單位,因此設計了一層針對 page(或稱分頁)的管理機制,該機制在 Linux Kernel 裡被稱為『Buddy System (buddy allocator,簡稱 buddy)』,buddy 是 Kernel 最底層的記憶體管理機制,日後所有的記憶體配置,最後都要經過 buddy 才能取得或釋放記憶體。

可以藉由觀察當前 /proc/buddyinfo ,了解目前的記憶體使用情況,當然,是以 page 為單位:
$ cat /proc/buddyinfo
Node 0, zone      DMA     76     71     66     50     33     17      5      1      1      1      0
Node 0, zone   Normal  22301   6425     45      0      1      1      1      1      1      1      0
Node 0, zone  HighMem     97     13      6     10      3      0      2      0      0      0      0


如果沒有什麼意外,/proc/buddyinfo 列會出了三個 zone ,分別是 DMA、Normal、HighMem,這三種 zone 的分類,是以 Physical Memory 位置的範圍而區分,在 IA-32 架構上 為:
  • DMA (16MB以下)
  • Normal (16MB~896MB)
  • HighMem (896MB以上)
不 過,由於 Buddy System 是一個很抽象且基礎的機制,對一般的 Driver 開發來說,並不是非常好用,而且,對習慣 C 語言的開發者來說,是相當不合情理的存在。體會一下這樣奇怪的習慣:透過 buddy 的 __get_free_pages() 和 free_pages() 等 functions 取得的記憶體,是以 page 為單位來計算(在 IA-32 上大小為 4096 bytes),而不是使用以 1 byte 為單位來配置。

但是,並非不能直接使用 buddy 提供的 functions 做 Linux Driver 的開發,而是有相當的困難性(如果你想全程使用,請先讓小弟尊稱您一下牛人 :P)。一個最簡單可能發生的例子,就是不當使用 page (一個單位數量)的記憶體,易造成記憶體的浪費和 fragmentation。所以,對一般 Driver 的開發者,除非必要,其實不應該要負責處理這樣低階的記憶體問題。

Slab Allocator

有鑑於此,Linux Kernel 就在 buddy 之上,更進一步設計了『智慧型』機制 -『Slab Allocator(簡稱 Slab)』,來確保記憶體分頁的配置效率和完整性,也使其他開發者有更好的 API 和機制可以操作記憶體。

Slab 算是 Kernel 裡最早的一種演算法,事實上,除了 Slab 之外,Linux Kernel 已經實作出數種演算法,以優化記憶體的配置機制。前面提到,Kernel 的底層是以 page 為記憶體配置的單位,因此,哪怕只是需要 1 Byte 的空間,都會佔用一個 page,所以良好的 Slab 演算法,才能盡可能避免記憶體浪費和破碎的問題。截至目前為止,Linux Kernel 所支援的演算法,除 Slab 外另有:
  • SLOB Allocator
  • SLUB Allocator
此外,雖演算法不同,習慣上,在 Linux Kernel 裡還是統稱為『Slab Allocator』,沿用舊有的稱呼以表示該層級的記憶體管理機制。

* 註:Linux Kernel 2.6.23 之後已改用 SLUB 當做預設演算法。

Slab Allocator 實作了一個 cache 的架構(這裡的 cache 並非意指快取),對系統程式下的記憶體需求群組化,以達到管理的目的。一般的程式可以藉由向 Slab 註冊 cache,以得到記憶體的配置。

要知道目前系統上有那些 cache 在使用,可以查看 /proc/slabinfo,亦或者可用指令工具 slabtop 查看。
$ slabtop
Active / Total Objects (% used)    : 858912 / 913334 (94.0%)
Active / Total Slabs (% used)      : 34472 / 34472 (100.0%)
Active / Total Caches (% used)     : 91 / 151 (60.3%)
Active / Total Size (% used)       : 124788.54K / 129749.01K (96.2%)
Minimum / Average / Maximum Object : 0.01K / 0.14K / 4096.00K

 OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME                 
599140 599140 100%    0.13K  20660       29     82640K dentry
174267 134508  77%    0.05K   2601       67     10404K buffer_head
62448  62337  99%    0.48K   7806        8     31224K ext3_inode_cache
20527  13331  64%    0.28K   1579       13      6316K radix_tree_node
 9706   7895  81%    0.08K    211       46       844K vm_area_struct
 7980   7779  97%    0.04K     95       84       380K sysfs_dir_cache
 7345   7100  96%    0.03K     65      113       260K size-32
 6372   5440  85%    0.06K    108       59       432K size-64
 5040   4521  89%    0.19K    252       20      1008K filp
 4318   3873  89%    0.01K     17      254        68K anon_vma
 2576   2546  98%    0.04K     28       92       112K Acpi-Operand
 1859   1756  94%    0.02K     11      169        44K Acpi-Namespace
  945    924  97%    0.43K    105        9       420K shmem_inode_cache
  780    610  78%    0.12K     26       30       104K size-96
  744    688  92%    0.50K     93        8       372K size-512
  737    710  96%    0.35K     67       11       268K proc_inode_cache
  648    130  20%    0.05K      9       72        36K journal_head
  572    285  49%    0.33K     52       11       208K inode_cache
  493    476  96%    0.13K     17       29        68K idr_layer_cache
  470    443  94%    0.38K     47       10       188K sock_inode_cache
  405    405 100%    0.44K     45        9       180K UNIX
  384    357  92%    1.00K     96        4       384K size-1024
  280    180  64%    0.19K     14       20        56K skbuff_head_cache
  254      2   0%    0.01K      1      254         4K revoke_table
  240    240 100%    0.12K      8       30        32K size-128
  234    192  82%    0.05K      3       78        12K task_delay_info
  203    121  59%    0.02K      1      203         4K biovec-1
  203      3   1%    0.02K      1      203         4K fasync_cache
  203      4   1%    0.02K      1      203         4K revoke_record
  184    138  75%    0.04K      2       92         8K inotify_watch_cache
  180    180 100%    0.19K      9       20        36K size-192


* 註:kmalloc() 所取得的記憶體,會以『size-*』的名稱存在。

當然不止如此,Linux 的記憶體管理還包括例外的特殊管道,如 vmalloc() 等,此外,Kernel Stack 也是一個很重要的機制,可惜短短篇幅無法一下說明完整,日後有時間再行補上。
阅读(1508) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~