【Android Linux內存及性能優化】(六) 系統內存的優化

本文接着
【Android Linux內存及性能優化】(一) 進程內存的優化 - 堆段
【Android Linux內存及性能優化】(二) 進程內存的優化 - 棧段 - 環境變量 - ELF
【Android Linux內存及性能優化】(三) 進程內存的優化 - ELF執行文件的 數據段-代碼段
【Android Linux內存及性能優化】(四) 進程內存的優化 - 動態庫- 靜態庫
【Android Linux內存及性能優化】(五) 進程內存的優化 - 線程

一、內存篇

1.1 系統當前可用內存

1.2 進程的內存使用

1.3 進程內存優化

1.4 系統內存優化

1.4.1 守護進程的內存使用

在設備開機之後,你會發現已經有很多進程在運行,這些進程將一直存活,直到設備關機,我們把這類進程稱爲守護進程。

守護進程對系弘的內存使用影響巨大:
(1)由於守護進程一直存活,所以其所佔用的內存將不會被釋放。
(2)一個進程即使什麼事情都不做,它引用了一些動態庫,也會佔用大量的物理內存。
(3)由於守護進程的生存週期很長,其哪怕只有一點內存泄漏,也會導致系統的內存耗盡。

進程一旦退出,其所佔用的內存存將被 Linux內核收回,所以對那些生存週期很短的進程來講,即使有些內存泄漏,其對系統內存使用影響並不大。

因些應該儘量減少系統中守護進程的數量,對於那些提供服務的守護進程來講,儘量做到在進程需要的時候來啓動,在不需要的時候退出。


下面就來詳細描述如何減少守護進程的數量。

首先爲什麼會存在守護進程? 原因主要兩點:

  1. 系統需要守護進程來偵聽某些事件。
    在設計守護進程時,開發人員往往沒有區分其中的常駐部分和非常駐部分,
    在偵聽到一個事件後,直接啓動相應的業務邏輯,而在這些業務邏輯執行完之後,並不會將本已無用的業務邏輯部分釋放。
    這樣就造成了偵聽部分與業務邏輯部分混在一起都作爲守護進程,
    而使得守護進程部分邏輯比較複雜,一方面佔用了大量的內存,另一方面也增大了內存泄漏的機率。

    因些建議將守護進程明確分爲常駐部分和非常駐部分,分別讓不同的進程來完成,將常駐內存部分的邏輯儘量簡化

    更進一步,可以考慮將幾個守護進程的偵聽事件部分合併到一個守護進程,當負責偵聽的守護進程收到消息後,再去啓動相應的業務邏輯。

    在這一方面,inetd 是最好的例子,其常駐內部部分可以偵聽 telnet、ftp等端口,在有用戶該問後,又會創建相應的進程爲用戶提供服務。


  1. 有些進程提供服務的響應時間達不到要求,開發人員便將其放在設備開機時啓動,所以轉變爲了守護進程。
    首先需要考慮加快進程的啓動速度,從而使服務進程達到按需啓動的需求,這個後續分析。
    除了優化加載動態庫、使用 Prelink 等方法外,還可以採用一些進程調度的方法來減少守護進程對於內存的影響。

1.4.2 tmpfs 分區

在LInux 中,爲了加快對文件的讀寫,基於內存建立了一個文件系統,稱爲 ramdisk 或者 tmpfs。
對於該文件系統的訪問,都將直接操作物理內存,因此而要比訪問Flash 快得多。

在做系統內存優化時,不要忘掉這塊內存。

ciellee@sh:~/work/code/simcom_220c_sop_1028_0426$ df  -H
Filesystem      Size  Used Avail Use% Mounted on
udev            8.4G     0  8.4G   0% /dev
tmpfs           1.7G   11M  1.7G   1% /run
/dev/sda8       706G  520G  150G  78% /
tmpfs           8.4G  180M  8.2G   3% /dev/shm
tmpfs           5.3M  4.1k  5.3M   1% /run/lock
tmpfs           8.4G     0  8.4G   0% /sys/fs/cgroup
/dev/loop0       99M   99M     0 100% /snap/core/9066

可以看出,tmpfs 文件分區爲8.4G。

在對這個文件分區進行讀寫時,要時刻提醒自已,它是佔用物理內存的,在該分區上的文件,不需要的時候應及時刪除。


1.4.3 Cache 緩存 和 Buffer 緩衝

前面講到, 系統中空閒內存 = MemFree + Buffers + Cached。
下面我們來看下 Cache 和 Buffer 分別是什麼。

1.4.3.1 Cache 緩存

Cache 也稱緩存,是把從Flash 中讀取的數據保存起來,
若再次讀取該塊數據時,就不需要去讀取Flash 了,直接從緩存中讀取,從而提高讀取文件的速度。

Cache 緩存的數據會根據讀取頻率進行組織,把最頻繁讀取的內容 放在最容易找到的位置,把不再讀的內容不斷往後排,直至從中刪掉。

在程序執行過程中,發現某些指令不在內存中,便會產生 page fault,而將代碼段的數據載入到物理內存。當進程退出後,代碼段所佔用的內存不會完全丟棄,而是作爲Cache 緩存在Linux 系統中。當進程運行時,Cache 的代碼指令越多,代碼段產生 page fault 的機率越小,程序的執行速度也越快,這便是Cache 存在的理由。


1.4.3.2 Buffer 緩衝

Buffer 也稱緩衝,是根據Flash 讀寫設計的,把分散的寫操作集中進行,減小Flash 寫的次數,從而提高系統性能。


Cache 和 Buffer 的區別,簡單來說,兩者都是RAM 中的數據,
Buffer 是緩衝即將寫入磁盤的數據, 而 Cache 是緩存從磁盤中讀取出來的數據。


在系統內存不足時,Linux 內核會將一部分 Cache 和 Buffer 釋放,供進程使用,因此Cache 和Buffer 對於進程的內存使用並沒有影響。

可以通過 cat /proc/meminfo 來了解系統中 Cache 和Buffer 的大小:

ciellee@sh:~/work/code/simcom_220c_sop_1028_0426$ cat /proc/meminfo 
MemTotal:       16281312 kB
MemFree:          178828 kB
MemAvailable:   13359384 kB
Buffers:          426416 kB
Cached:         13052476 kB
SwapCached:            0 kB
Active:          2841180 kB
Inactive:       12108016 kB

1.4.3.3 內存回收

在 LInux 中,有一個內核進程 kswapd ,其專門負責回收內存。

在 kswapd 中,有2 個閾值: pages_high 和 pages_low ,
當空閒內存頁的數量低於 pages_low 的時候,kswapd 進程就會掃描內存並且每次釋放出 32 個 free pages,直到 free page 的數量到達 pages_high。


(1)kswapd 回收內存有如下原則:
  1. 如果物理頁面不量 dirty page,就將物理頁面回收。
    進程中如下內存可能是非 dirty page頁面:
    (1)代碼段:其權限是隻讀屬性,不可能被改寫,所以其所佔的物理內存,都不是dirty page。
    (2)數據段:其權限是可讀、可寫,所以其所佔的物理內存可能是 dirty page,也可能不是。
    (3)堆段:其權限是可讀、可寫,空容全是通過程序改寫的,所以其所佔用的物理內存,全部是 dirty page。
    (4)棧段 和 堆段 相同,其所佔的物理內存,全部是 dirty page。
    (5)共享內存,其所佔的物理內存,全部是 dirty page。

    綜上: 這條規則主要面向的是進程的代碼段 和 未修改的數據段。
    如果你做過長時間的系統進程使用分析,就會發現,在進程跑了一段時間後,其代碼所佔的物理內存減少了,這就是代碼段內存回收的結果。

  2. 如果物理頁面已經修改 並且 可以備份迴文件系統,就調用 pdflush 將內存中的內容 和文件系統進行同步。同步完成後,就可以將內存釋放。
    比如,當一個文件在內存中進行修改,pdflush 負責將其寫回磁盤,其主要針對的是下 Buffers。

  3. 如果物理頁面已經修改但是沒有任何磁盤的備份,就將其寫入 swap 分區。
    實際上大部分嵌入式設備很少有交換分區,因此這條規則根本不起作用。

kswapd 在回收內存過程中還有兩個重要的方法:
一是 LMR (Low on memory reclaiming),另一個是 OMK(Out of Memory Killer)。

當分配內存失敗的時候,LMR將會起作用,失敗的原因是 kswapd 不能提供足夠的空閒內存,這個時候LMR 會每次釋放1024 個垃圾頁直到內存分配成功。
當LMR 不能快速釋放內存的時候,OMK 就開始起作用,OMK 會採用一個選擇算法來決定殺死某些進程,選定進程後,就會發送信號 SIGKILL,這就會使內存立即被釋放。

(2)OMK 選擇進程的標準如下:
  1. 進程佔用大量的內存。
  2. 進程只會損失少量工作。
  3. 進程具有低的靜態優先級。
  4. 進程不屬於 root 用戶。

1.4.3.4 /proc/sys/vm/優化

可以通過修改 /proc/sys/vm 下面的文件,設置一些參數,來影響 LInux內核的一些內存操作行爲。

修改 /proc/ 下文件的方法:

  1. # echo 1 > /proc/sys/vm/block_dump
    該文件表示是否打開 Block Debug 模式,用於記錄所有的讀寫及 Dirty Block寫回動作。
    缺省設置 :0,禁用 Block Debug。

  2. # echo 10 > /proc/sys/vm/dirty_background_ratio
    該文件表示髒數據到達系統整體內存的百分比,此時觸發 pdflush 進程把髒數據寫回磁盤。
    缺省設置:10, 10%

  3. # echo 3000 > /proc/sys/vm/dirty_expire_centisece
    該文件表示如果髒數據在內存中駐留時間超過該值,pdflush 進程在下一次將把這些數據寫回磁盤。
    缺省設置:3000, (1/100)s

  4. # echo 40 > /proc/sys/vm/dirty_ratio
    該文件表示如果進程產生的髒數據到達系統整體內存的百分比,此時進程自行把髒數據寫回磁盤。
    缺省設置:40, 40%

  5. # echo 500 > /proc/sys/vm/dirty_writeback_centisecs
    該文件表示pdflush 進程週期間隔多久把髒數據寫回磁盤。
    缺省設置:500, (1/100)s

  6. # echo 100 > /proc/sys/vm/vfs_cache_pressure
    該文件表示內核回收用於directory 和 inode cache 內存的傾向,
    缺省 100 表示內核將根據 pagecache 和 swapcache ,把 directory 和 inode cache 保持在一個合理的百分比;
    降低該值於 100,將導致內核傾向於保留 directory 和 inode cache 。
    增加該值超過 100 ,將導致內核傾向於回收 directory 和 inode cache 。
    缺省設置:100

  7. # echo 724 > /proc/sys/vm/min_free_kbytes
    該文件表示強制 Linux VM 最低保留多少空閒內存(KB),缺省值:724

  8. # cat /proc/sys/vm/nr_pdflush_threads
    該文件表示當前正在運行的 pdflush 進程數量,在I/O 負載高的情況下,內核會自動增加更多的pdflush 進程,缺省值:2(只讀)

  9. # echo 0 > /proc/sys/vm/overcommit_memory
    該文件指定了內核針對內存分配的策略,其值可以是:0、1、2,缺省值:0
    0:表示內核將檢查是否有足夠的可用內存供應進使用,如果有足夠的可用內存,內存申請允許,否則內存申請失敗,並把錯誤返回給應用進程。
    1:表示內核允許分配所有的物理內存,而不管當前的內存狀態如何。
    2:表示內核允許分配超進所有物理內存和交換空間總和的內存。

  10. # echo 50 > /proc/sys/vm/overcommit_ratio
    該文件表示,如果 overcommit_memory = 2 ,可以過載內存的百分比,通過以下公式來計算系統整估可用內存:
    系統可分配內存 = 交換空間 + 物理內存 × overcommit_ratio / 100。
    缺省設置:50%

  11. # echo 3 > /proc/sys/vm/page-cluster
    該文件表示在寫一次到swap 區的時候寫入的頁面數量,0: 表示1頁, 1:表示2頁,2表示4頁, 缺省3:2^3=8頁。

  12. # echo 60 > /proc/sys/vm/swapiness
    該文件表示,系統進行交換行爲的程序,數值(0~100)越高,越可能發生磁盤交換,缺省60

  13. # echo 0 > /proc/sys/vm/legacy_va_layout
    該文件表示是否使用最新的32位共享內存 mmap() 系統調用,Linux 支持的共享內存分配方式包括mmap(), Posix, System VIPC,缺省 0
    0:表示使用最新的32位 mmap() 系統調用
    1:表示使用 2.4 內核提供的系統調用

  14. # cat /proc/sys/vm/nr_hugepages
    該文件表示系統保留的 hugetlb 頁數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章