目錄
1. 內存使用情況分析 2. 內存泄漏(memory leak) 3. Valgrind使用
1. 內存使用情況分析
0x1: 系統總內存的分析
可以從proc目錄下的meminfo文件了解到當前系統內存的使用情況匯總,其中
可用的物理內存 = memfree + buffers + cached
當memfree不夠時,內核會通過回寫機制(pdflush線程)把cached和buffered內存回寫到后備存儲器,從而釋放相關內存供進程使用,或者通過手動方式顯式釋放cache內存:
echo 3 > /proc/sys/vm/drop_caches
$cat /proc/meminfo MemTotal: 8388608 kB MemFree: 6880760 kB Buffers: 0 kB Cached: 1490828 kB SwapCached: 0 kB Active: 1224960 kB Inactive: 282832 kB Active(anon): 17028 kB Inactive(anon): 348 kB Active(file): 1207932 kB Inactive(file): 282484 kB Unevictable: 0 kB Mlocked: 4884 kB SwapTotal: 1999864 kB SwapFree: 1999864 kB Dirty: 596 kB Writeback: 0 kB AnonPages: 202420 kB Mapped: 37400 kB Shmem: 4736 kB Slab: 1937380 kB SReclaimable: 1739632 kB SUnreclaim: 197748 kB KernelStack: 15920 kB PageTables: 30188 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 51319712 kB Committed_AS: 13594600 kB VmallocTotal: 34359738367 kB VmallocUsed: 662532 kB VmallocChunk: 34359070640 kB HardwareCorrupted: 0 kB AnonHugePages: 0 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB DirectMap4k: 4096 kB DirectMap2M: 2076672 kB DirectMap1G: 98566144 kB
0x2: 進程使用內存統計
在32位操作系統中,每個進程擁有4G的虛擬內存空間,其中0~3GB是每個進程的私有用戶空間,這個空間對系統中其他進程是不可見的。3~4GB是linux內核空間,由系統所有的進程以及內核所共享的。通過訪問/proc/{pid}/下相關文件,可以了解每個線程(進程)虛擬內存空間的使用情況,從而了解每個線程(進程)所消耗內存的多少
可以通過查看/proc/{pid}/maps文件來獲取相關的虛擬地址空間內容
sudo cat /proc/1417/maps 2b4494635000-2b449463b000 r-xp 00000000 03:01 819306 /sbin/klogd 2b449463b000-2b449463c000 rw-p 2b449463b000 00:00 0 2b449483b000-2b449483c000 rw-p 00006000 03:01 819306 /sbin/klogd 2b449483c000-2b449483d000 rw-p 2b449483c000 00:00 0 2b449483d000-2b4494859000 r-xp 00000000 03:01 409674 /lib64/ld-2.5.so 2b4494859000-2b449485b000 rw-p 2b4494859000 00:00 0 2b4494a59000-2b4494a5a000 r--p 0001c000 03:01 409674 /lib64/ld-2.5.so 2b4494a5a000-2b4494a5b000 rw-p 0001d000 03:01 409674 /lib64/ld-2.5.so 2b4494a5b000-2b4494ba9000 r-xp 00000000 03:01 409683 /lib64/libc-2.5.so 2b4494ba9000-2b4494da9000 ---p 0014e000 03:01 409683 /lib64/libc-2.5.so 2b4494da9000-2b4494dad000 r--p 0014e000 03:01 409683 /lib64/libc-2.5.so 2b4494dad000-2b4494dae000 rw-p 00152000 03:01 409683 /lib64/libc-2.5.so 2b4494dae000-2b4494db4000 rw-p 2b4494dae000 00:00 0 2b44adeca000-2b44adeeb000 rw-p 2b44adeca000 00:00 0 [heap] 7fff58134000-7fff58149000 rw-p 7ffffffe9000 00:00 0 [stack] 7fff58162000-7fff58165000 r-xp 7fff58162000 00:00 0 [vdso] ffffffffff600000-ffffffffffe00000 ---p 00000000 00:00 0 [vsyscall]
當進程申請內存時,實際上是glibc中內置的內存管理器接收了該請求,隨着進程申請內存的增加,內存管理器會通過系統調用陷入內核,從而為進程分配更多的內存
針對堆段的管理,內核提供了兩個系統調用brk和mmap,brk用於更改堆頂地址,而mmap則為進程分配一塊虛擬地址空間
當進程向glibc申請內存時,如果申請內存的數量大於一個閥值的時候,glibc會采用mmap為進程分配一塊虛擬地址空間,而不是采用brk來擴展堆頂的指針。缺省情況下,此閥值是128K,可以通過函數來修改此值
如果在實際的調試過程中,懷疑某處發生了內存泄露,可以查看該進程的maps表,看進程的堆段或者mmap段的虛擬地址空間是否持續增加,如果是,說明很可能發生了內存泄露,如果mmap段虛擬地址空間持續增加,還可以看到各個段的虛擬地址空間的大小,從而可以確定是申請了多大的內存,對調試內存泄露類問題可以起到很好的定位作用
Relevant Link:
http://os.51cto.com/art/201304/388070.htm
2. 內存泄漏(memory leak)
內存泄漏(memory leak),指由於疏忽或錯誤造成程序未能釋放已經不再使用的內存的情況
在編程時進行動態內存分配是非常必要的,它可以在程序運行的過程中幫助分配所需的內存,而不是在進程啟動的時候就進行分配。然而有效地管理這些內存同樣也是非常重要的
在大型的、復雜的應用程序中,內存泄漏是常見的問題,當以前分配的一片內存不再需要使用或無法訪問時,但是卻並沒有釋放它,那么對於該進程來說,會因此導致總可用內存的減少,這時就出現了內存泄漏
0x1: 內存泄漏的發生方式
1. 常發性內存泄漏 發生內存泄漏的代碼會被多次執行到,每次被執行的時候都會導致一塊內存泄漏 2. 偶發性內存泄漏 發生內存泄漏的代碼只有在某些特定環境或操作過程下才會發生。常發性和偶發性是相對的。對於特定的環境,偶發性的也許就變成了常發性的。所以測試環境和測試方法對檢測內存泄漏至關重要 3. 一次性內存泄漏 發生內存泄漏的代碼只會被執行一次,或者由於算法上的缺陷,導致總會有一塊且僅有一塊內存發生泄漏 4. 隱式內存泄漏 程序在運行過程中不停的分配內存,但是直到結束的時候才釋放內存。嚴格的說這里並沒有發生內存泄漏,因為最終程序釋放了所有申請的內存。但是對於一個服務器程序,需要運行幾天,幾周甚至幾個月,不及時釋放內存也可能導致最終耗盡系統的所有內存。所以,我們稱這類內存泄漏為隱式內存泄漏
0x2: 常用內存泄漏檢測工具
C/C++ 1. Valgrind: Debugging and profiling Linux programs, aiming at programs written in C and C++ 2. ccmalloc: Linux和Solaris下對C和C++程序的簡單的使用內存泄漏和malloc調試庫 3. LeakTracer: Linux、Solaris和HP-UX下跟蹤和分析C++程序中的內存泄漏 4. Electric Fence: Linux分發版中由Bruce Perens編寫的malloc()調試庫 5. Leaky: Linux下檢測內存泄漏的程序 6. Dmalloc: Debug Malloc Library 7. MEMWATCH: 由Johan Lindh編寫,是一個開放源代碼C語言內存錯誤檢測工具,主要是通過gcc的precessor來進行 8. KCachegrind: A visualization tool for the profiling data generated by Cachegrind and Calltree Java 1. Memory Analyzer: 是一款開源的JAVA內存分析軟件,查找內存泄漏,能容易找到大塊內存並驗證誰在一直占用它,它是基於Eclipse RCP(Rich Client Platform),可以下載RCP的獨立版本或者Eclipse的插件 2. JProbe: 分析Java的內存泄漏 3. JProfiler: 一個全功能的Java剖析工具,專用於分析J2SE和J2EE應用程序。它把CPU、執行緒和內存的剖析組合在一個強大的應用中,GUI可以找到效能瓶頸、抓出內存泄漏、並解決執行緒的問題 4. JRockit: 用來診斷Java內存泄漏並指出根本原因,專門針對Intel平台並得到優化,能在Intel硬件上獲得最高的性能 5. YourKit .NET & Java Profiling: 業界領先的Java和.NET程序性能分析工具 6. AutomatedQA: AutomatedQA的獲獎產品performance profiling和memory debugging工具集的下一代替換產品,支持Microsoft, Borland, Intel, Compaq 和 GNU編譯器。可以為.NET和Windows程序生成全面細致的報告,從而幫助您輕松隔離並排除代碼中含有的性能問題和內存/資源泄露問題。支持.Net 1.0,1.1,2.0,3.0和Windows 32/64位應用程序 7. Compuware DevPartner Java Edition: 包含Java內存檢測,代碼覆蓋率測試,代碼性能測試,線程死鎖,分布式應用等幾大功能模塊 .NET 1. .NET Memory Profiler: 找到內存泄漏並優化內存使用針對C#,VB.Net,或其它.Net程序 2. Windows Leaks Detector: 探測任何Win32應用程序中的任何資源泄漏(內存,句柄等),基於Win API調用鈎子 3. DTrace: 一款開源動態跟蹤Dynamic Tracing,能在Unix類似平台運行,用戶能夠動態檢測操作系統內核和用戶進程,以更精確地掌握系統的資源使用狀況,提高系統性能,減少支持成本,並進行有效的調節 4. IBM Rational PurifyPlus: 幫助開發人員查明C/C++、托管.NET、Java和VB6代碼中的性能和可靠性錯誤。PurifyPlus 將內存錯誤和泄漏檢測、應用程序性能描述、代碼覆蓋分析等功能組合在一個單一、完整的工具包中 5. Parasoft Insure++: 針對C/C++應用的運行時錯誤自動檢測工具,它能夠自動監測C/C++程序,發現其中存在着的內存破壞、內存泄漏、指針錯誤和I/O等錯誤。並通過使用一系列獨特的技術(SCI技術和變異測試等),徹底的檢查和測試我們的代碼,精確定位錯誤的准確位置並給出詳細的診斷信息。能作為Microsoft Visual C++的一個插件運行 6. Compuware DevPartner for Visual C++ BoundsChecker Suite: 為C++開發者設計的運行錯誤檢測和調試工具軟件。作為Microsoft Visual Studio和C++ 6.0的一個插件運行 7. Electric Software GlowCode: 包括內存泄漏檢查,code profiler,函數調用跟蹤等功能。給C++和.Net開發者提供完整的錯誤診斷,和運行時性能分析工具包 FireFox / IE 1. Leak Monitor: 一個Firefox擴展,能找出跟Firefox相關的泄漏類型 2. IE Leak Detector (Drip/IE Sieve): Drip和IE Sieve leak detectors幫助網頁開發員提升動態網頁性能通過報告可避免的因為IE局限的內存泄漏。 3. JavaScript Memory Leak Detector: 微軟全球產品開發歐洲團隊(Global Product Development- Europe team, GPDE) 發布的一款調試工具,用來探測JavaScript代碼中的內存泄漏,運行為IE系列的一個插件
0x3: 內存檢查原理
Memcheck檢測內存問題的原理如下圖所示
Memcheck 能夠檢測出內存問題,關鍵在於其建立了兩個全局表
1. Valid-Value表 對於進程的整個地址空間中的每一個字節(byte),都有與之對應的 8 個 bits;對於 CPU 的每個寄存器,也有一個與之對應的 bit 向量。這些 bits 負責記錄該字節或者寄存器值是否具有有效的、已初始化的值 2. Valid-Address表 對於進程整個地址空間中的每一個字節(byte),還有與之對應的 1 個 bit,負責記錄該地址是否能夠被讀寫
檢測原理
1. 當要讀寫內存中某個字節時,首先檢查這個字節對應的 A bit(Valid-Adress Map)。如果該A bit顯示該位置是無效位置,memcheck 則報告讀寫錯誤 2. 內核(core)類似於一個虛擬的 CPU 環境,這樣當內存中的某個字節被加載到真實的 CPU 中時,該字節對應的 V bit(Valid-Value Map) 也被加載到虛擬的 CPU 環境中。一旦寄存器中的值,被用來產生內存地址,或者該值能夠影響程序輸出,則 memcheck 會檢查對應的V bits,如果該值尚未初始化,則會報告使用未初始化內存錯誤
Relevant Link:
http://blog.csdn.net/ithomer/article/details/6928318 http://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/
3. Valgrind使用
Valgrind是一套Linux下,開放源代碼(GPL V2)的仿真調試工具的集合。Valgrind由內核(core)以及基於內核的其他調試工具組成。內核類似於一個框架(framework),它模擬了一個CPU環境,並提供服務給其他工具: 而其他工具則類似於插件(plug-in),利用內核提供的服務完成各種特定的內存調試任務
Valgrind包括如下一些工具
1. Memcheck 這是valgrind應用最廣泛的工具,一個重量級的內存檢查器,能夠發現開發中絕大多數內存錯誤使用情況,比如:使用未初始化的內存,使用已經釋放了的內存,內存訪問越界等。這也是本文將重點介紹的部分,Valgrind 中包含的 Memcheck 工具可以檢查以下的程序錯誤 1) 使用未初始化的內存 (Use of uninitialised memory) 2) 使用已經釋放了的內存 (Reading/writing memory after it has been free’d) 3) 使用超過malloc分配的內存空間(Reading/writing off the end of malloc’d blocks) 4) 對堆棧的非法訪問 (Reading/writing inappropriate areas on the stack) 5) 申請的空間是否有釋放 (Memory leaks – where pointers to malloc’d blocks are lost forever) 6) malloc/free/new/delete申請和釋放內存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete []) 7) src和dst的重疊(Overlapping src and dst pointers in memcpy() and related functions) 8) 重復free 2. Callgrind 它主要用來檢查程序中函數調用過程中出現的問題 3. Cachegrind 它主要用來檢查程序中緩存使用出現的問題 4. Helgrind 它主要用來檢查多線程程序中出現的競爭問題 5. Massif 它主要用來檢查程序中堆棧使用中出現的問題 6. Extension 可以利用core提供的功能,自己編寫特定的內存調試工具
0x1: 編譯安裝
wget http://valgrind.org/downloads/valgrind-3.4.1.tar.bz2 tar xvf valgrind-3.4.1.tar.bz2 cd valgrind-3.4.1/ ./configure --prefix/home/zhenghan.zh/valgrind make make install
0x2: 檢測使用
為了使valgrind發現的錯誤更精確,如能夠定位到源代碼行,建議在編譯時加上-g參數,編譯優化選項請選擇O0,雖然這會降低程序的執行效率
#include <stdlib.h> void fun() { int *p = (int*)malloc(10 * sizeof(int)); //內存越界寫入 p[10] = 0; } int main(int argc, char* argv[]) { fun(); return 0; } //gcc –g –O0 sample.c –o sample
運行valgrind
/home/zhenghan.zh/valgrind/bin/valgrind --tool=memcheck --leak-check=full /home/zhenghan.zh/memcheck/sample
/home/zhenghan.zh/valgrind/bin/valgrind /home/zhenghan.zh/memcheck/sample
Relevant Link:
http://zyan.cc/post/419/ http://www.ibm.com/developerworks/cn/linux/l-cn-valgrind/
Copyright (c) 2014 LittleHann All rights reserved