/proc/meminfo分析(一)


本文主要分析/proc/meminfo文件的各種輸出信息的具體含義。

一、MemTotal

MemTotal對應當前系統中可以使用的物理內存。

這個域實際是對應內核中的totalram_pages這個全局變量的,定義如下:

unsigned long totalram_pages __read_mostly;

該變量表示當前系統中Linux內核可以管理的所有的page frame的數量。注意:這個值並不是系統配置的內存總數,而是指操作系統可以管理的內存總數。

內核是如何得到totalram_pages這個值的呢?是在初始化的過程中得到的,具體如下:我們知道,在內核初始化的時候,我們可以通過memblock模塊來管理內存布局,從而得到了memory type和reserved type的內存列表信息。在初始化階段如果有內存分配的需求,那么也可以通過memblock來完成,直到伙伴系統初始化完成,而在這個過程中,memory type的那些page frame被一個個的注入到各個zone的free list中,同時用totalram_pages 來記錄那個時間點中空閑的page frame數量。這個點也就是伙伴系統的一個初始內存數量的起點。

舉一個實際的例子:我的T450的計算機,配置的內存是8G,也就是8388608KB。但是MemTotal沒有那么多,畢竟OS本身(正文段、數據段等等)就會占用不少內存,此外還有系統各種保留的內存,把這些都去掉,Linux能管理的Total memory是7873756KB。看來OS內存管理的開銷也不小啊。

 

二、MemFree

啟動的時候,系統確定了MemTotal的數目,但是隨着系統啟動過程,內核會動態申請內存,此外,用戶空間也會不斷創建進程,也會不斷的消耗內存,因此MemTotal可以簡單分成兩個部分:正在使用的和空閑的。MemFree表示的就是當前空閑的內存數目,這些空閑的page應該是掛在各個node的各個zone的buddy系統中。

具體free memory的計算如下:

freeram = global_page_state(NR_FREE_PAGES);

也就是把整個系統中在當前時間點上空閑的內存數目統計出來。

 

三、MemAvailable

所謂memory available,其實就是不引起swapping操作的情況下,我們能使用多少的內存。即便是free的,也不是每一個page都可以用於內存分配。例如buddy system會設定一個水位,一旦free memory低於這個水位,系統就會啟動page reclaim,從而可能引起swapping操作。因此,我們需要從MemFree這個數值中去掉各個節點、各個zone的預留的內存(WMARK_LOW)數目。當然,也是不是說那些不是空閑的頁面我們就不能使用,例如page cache,雖然不是空閑的,但是它也不過是為了加快性能而使用,其實也可以回收使用。當然,也不是所有的page cache都可以計算進入MemAvailable,有些page cache在回收的時候會引起swapping,這些page cache就不能算數了。此外,reclaimable slab中也有一些可以使用的內存,MemAvailable也會考慮這部分內存的情況。

總而言之,MemAvailable就是不需要額外磁盤操作(開銷較大)就可以使用的空閑內存的數量。

 

四、Buffers

其實新的內核已經沒有buffer cache了,一切都統一到了page cache的框架下了。因此,所謂的buffer cache就是塊設備的page cache。具體的統計過程是通過nr_blockdev_pages函數完成,代碼如下:

long nr_blockdev_pages(void)
{
    struct block_device *bdev;
    long ret = 0;
    spin_lock(&bdev_lock);
    list_for_each_entry(bdev, &all_bdevs, bd_list) {
        ret += bdev->bd_inode->i_mapping->nrpages;
    }
    spin_unlock(&bdev_lock);
    return ret;
}

我們知道,內核是通過address_space來管理page cache的,那么塊設備的address_space在哪里呢?這個稍微復雜一點,涉及多個inode,假設/dev/aaa和/dev/bbb都是指向同一個物理塊設備,那么open/dev/aaa和/dev/bbb會分別產生兩個inode,我們稱之inode_aaa和inode_bbb,但是最后一個塊設備的page cache還是需要統一管理起來,不可能分別在inode_aaa和inode_bbb中管理。因此,Linux構造了一個bdev文件系統,保存了系統所有塊設備的inode,我們假設該物理塊設備在bdev文件系統中的inode是inode_bdev。上面講了這么多的inode,其實塊設備的page cache就是在inode_bdev中管理的。

一般來說,buffers的數量不多,因為產生buffer的操作包括:

1、打開該block device的設備節點,直接進行讀寫操作(例如dd一個塊設備)

2、mount文件系統的時候,需要從相應的block device上直接把塊設備上的特定文件系統的super block相關信息讀取出來,這些super block的raw data會保存在該block device的page cache中

3、文件操作的時候,和文件元數據相關的操作(例如讀取磁盤上的inode相關的信息)也是通過buffer cache進行訪問。

Linux中最多處理的是2和3的操作,1的操作很少有。

 

五、Cached

讀寫普通文件的時候,我們並不會直接操作磁盤,而是通過page cache來加速文件IO的性能。Cached域描述的就是用於普通文件IO的page cache的數量,具體計算過程如下:

cached = global_page_state(NR_FILE_PAGES) -
            total_swapcache_pages() - i.bufferram;

系統中所有的page cache都會被記錄在一個全局的狀態中,通過global_page_state(NR_FILE_PAGES)可以知道這個數據,這個數據包括:

1、普通文件的page cache

2、block device 的page cache。參考上一節的描述。

3、swap cache。下一節會進一步描述。

對於Cached這個域,我們只關心普通文件的page cache,因此要從page cache的total number中減去buffer cache和swap cache。

 

六、SwapCached

其實上一節已經提及swap cache了,也歸屬於page cache中,具體計算如下:

unsigned long total_swapcache_pages(void)
{
    int i;
    unsigned long ret = 0;

    for (i = 0; i < MAX_SWAPFILES; i++)
        ret += swapper_spaces[i].nrpages;
    return ret;
}

和其他的page cache不一樣,swap cache並不是為了加快磁盤IO的性能,它是為了解決page frame和swap area之間的同步問題而引入的。例如:一個進程准備swap in一個page的時候,內核的內存回收模塊可能同時也在試圖將這個page swap out。為了解決這些這些同步問題,內核引入了swap cache這個概念,在任何模塊進行swap in或者swap out的時候,都必須首先去swap cache中去看看,而借助page descriptor的PG_locked的標記,我們可以避免swap中的race condition。

swap cache在具體實現的時候,仍然借用了page cache的概念,每一個swap area都有一個address space,管理該swap device(或者swap file)的page cache。因此,一個swap device的所有swap cache仍然是保存在對應address space的radix tree中(仍然是熟悉的配方,仍然是熟悉的味道啊)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM