Linux程序記憶體分析和記憶體洩漏定位

2022-05-04 03:24:08 字數 2654 閱讀 3164

在linux產品開發過程中,通常需要注意系統記憶體使用量,和評估單一程序的記憶體使用情況,便於我們選取合適的機器配置,來部署我們的產品。

linux本身提供了一些工具方便我們達成這些需求,檢視程序實時資源top工具,更詳細的程序記憶體堆疊情況,pmap工具,linux程序執行時狀態資訊也會儲存在proc目錄下,相應程序id目錄下,這裡有很豐富的資訊,先討論程序記憶體。

借助網上大部分人的說法,linux系統在記憶體分配上:記憶體充足時,盡量使用記憶體來快取一些檔案,從而加快程序的執行速度,而當記憶體不足時,會通過相應的記憶體**策略收回cache記憶體,供程序使用。

雖然在linux平台下做開發,但是對linux記憶體管理並不熟悉,不過上述說法,可以通過下面的方法來驗證:

一、系統記憶體。

在proc目錄下的meminfo檔案描述系統記憶體的使用情況,可用的物理記憶體=memfree+buffers+cached,下圖是suse10 的情況:

memtotal 是全部物理記憶體,我的虛擬器配置的是1g記憶體,memfree+buffers+cached = 438752,大概還有430m可用,因為我的機器上只跑著apache和redis程序。

當memfree不夠時,核心會通過回寫機制(pdflush執行緒)把cached和buffered記憶體回寫到後備儲存器,也可以通過手動方式顯式釋放cache記憶體

釋放後,buffers和cached 錶小了好多,memfree變大了許多,memfree+buffers+cached三者和大約仍然是430m。

二、程序記憶體

在32位作業系統中,每個程序擁有4g的虛擬記憶體空間,其中0~3gb是每個程序的私有使用者空間,這個空間對系統中其他程序是不可見的。3~4gb是linux核心空間,由系統所有的程序以及核心所共享的。通過訪問/proc//下相關檔案,可以檢視程序記憶體情況。

1、當前執行檔案的**段,該**段稱為text段。

2、執行檔案的資料段,主要儲存執行檔案用到的全域性變數,靜態變數。(全域性和static)

3、儲存全域性變數和動態產生的資料的堆。(堆)

4、用於儲存區域性變數和實現函式呼叫的棧。(棧)

5、採用mmap方式對映到虛擬位址空間中的記憶體段

這是我的機器上,redis 程序的情況,

**段,程式的**段需載入到記憶體中才可以執行。由於其唯讀,不會

被修改,所以在整個系統內共享。

第三行:從rwxp可知其許可權是可讀寫,可執行,位址空間向上增長,而且不對應檔案,是堆段,程序使用malloc申請的記憶體放在堆段。每個程序只有乙個堆段,不論是主程序,還是不同的執行緒申請的記憶體,都反映到到程序的堆段。堆段向上增長,最大可以增長到1gb的位置,即0x40000000,如果大於1gb,glibc將採用mmap的方式,為堆申請一塊記憶體。

第八行:是程序的棧區。關於棧段,每個執行緒都有乙個,如果程序中有多個執行緒,則包含多個棧段。

三、當前系統總記憶體的統計

1、程序占用的總記憶體可以通過上述maps表計算出來。

2、當系統執行起來以後,會把應用層相關的檔案掛載到tmpfs檔案系統下,海思系統下這部分大概有13m左右,這部分記憶體是以cache方式統計出來的,但是這部分記憶體cache無法通過**策略或者顯式的呼叫釋放掉。

3、根檔案系統ramdisk占用的記憶體。

4、當前系統保留記憶體的大小,可以通過檢視/proc/sys/vm/min_free_kbytes來獲取或者修改此記憶體的大小。

5、當然,當系統執行起來後,還應該留有一定的記憶體用於在硬碟讀寫時做cache或者網路負荷比較高時分配skb等,一般需要30m以上。

四、對除錯記憶體洩露類問題的一些啟示

當程序申請記憶體時,實際上是glibc中內建的記憶體管理器接收了該請求,隨著程序申請記憶體的增加,記憶體管理器會通過系統呼叫陷入核心,從而為程序分配更多的記憶體。

針對堆段的管理,核心提供了兩個系統呼叫brk和mmap,brk用於更改堆頂位址,而mmap則為程序分配一塊虛擬位址空間。

當程序向glibc申請記憶體時,如果申請記憶體的數量大於乙個閥值的時候,glibc會採用mmap為程序分配一塊虛擬位址空間,而不是採用brk來擴充套件堆頂的指標。預設情況下,此閥值是128k,可以通過函式來修改此值。

#include

intmallopt(int param, int value)

param的取值分別為m_mmap_threshold、m_mmap_max。

value的取值是以位元組為單位的。

m_mmap_threshold是glibc中申請大塊記憶體閥值,大於該閥值的記憶體申請,記憶體管理器將使用mmap系統呼叫申請記憶體,如果小於該閥值的記憶體申請,記憶體管理器使用brk系統呼叫擴充套件堆頂指標。

m_mmap_max是該程序中最多使用mmap分配位址段的數量。

如果在實際的除錯過程中,懷疑某處發生了記憶體洩露,可以檢視該程序的maps表,看程序的堆段或者mmap段的虛擬位址空間是否持續增加,如果是,說明很可能發生了記憶體洩露,如果mmap段虛擬位址空間持續增加,還可以看到各個段的虛擬位址空間的大小,從而可以確定是申請了多大的記憶體,對除錯記憶體洩露類問題可以起到很好的定位作用。

**:

使用memwatch跟蹤linux記憶體洩漏

參考 根據log可以查詢出申請了卻沒有釋放記憶體的行號。一 簡介 memwatch可以跟蹤程式中的記憶體洩漏和錯誤,能檢測雙重釋放 double free 錯誤釋放 erroneousfree 沒有釋放的記憶體 unfreed memory 溢位 overflow 下溢 underflow 等。解壓...

linux linux程序記憶體分析

在產品的開發中,通過對當前系統消耗記憶體總量的統計,可以對產品所需記憶體總量進行精確的評估,從而選擇合適的記憶體晶元與大小,降低產品的成本。在遇到記憶體洩露類問題時,經常會對此束手無策,本文通過對proc下程序相關的檔案進行分析,精確評估系統消耗記憶體的大小,還可以對記憶體洩露類問題的解決提供一種定...

Java程序記憶體分析

ps aux命令執行結果的幾個列的資訊的含義 user 程序所屬使用者 pid 程序id cpu 程序占用cpu百分比 mem 程序占用記憶體百分比 vsz 虛擬記憶體占用大小 單位 kb killobytes rss 實際記憶體占用大小 單位 kb killobytes tty 終端型別 stat...