當前位置:首頁 » 編程軟體 » 產品內存泄露能通過編譯檢查到嗎

產品內存泄露能通過編譯檢查到嗎

發布時間: 2022-07-08 08:57:17

⑴ 怎樣發現內存泄露

一、內存泄漏的檢查方法:
1.ccmalloc-linux和Solaris下對C和C++程序的簡單的使用內存泄漏和malloc調試庫。
2.Dmalloc-Debug Malloc Library.
3.Electric Fence-Linux分發版中由Bruce Perens編寫的malloc()調試庫。
4.Leaky-Linux下檢測內存泄漏的程序。
5.LeakTracer-Linux、Solaris和HP-UX下跟蹤和分析C++程序中的內存泄漏。
6.MEMWATCH-由Johan Lindh編寫,是一個開放源代碼c語言內存錯誤檢測工具,主要是通過gcc的precessor來進行。
7.Valgrind-Debugging and profiling Linux programs, aiming at programs written in C and C++.
8.KCachegrind-A visualization tool for the profiling data generated by Cachegrind and Calltree.
9.IBM Rational PurifyPlus-幫助開發人員查明C/C++、託管.NET、Java和VB6代碼中的性能和可靠性錯誤。PurifyPlus 將內存錯誤和泄漏檢測、應用程序性能描述、代碼覆蓋分析等功能組合在一個單一、完整的工具包中。

二、內存泄漏的簡單介紹:
內存泄漏也稱作「存儲滲漏」,用動態存儲分配函數動態開辟的空間,在使用完畢後未釋放,結果導致一直占據該內存單元。直到程序結束。(其實說白了就是該內存空間使用完畢之後未回收)即所謂內存泄漏。
內存泄漏形象的比喻是「操作系統可提供給所有進程的存儲空間正在被某個進程榨乾」,最終結果是程序運行時間越長,佔用存儲空間越來越多,最終用盡全部存儲空間,整個系統崩潰。所以「內存泄漏」是從操作系統的角度來看的。這里的存儲空間並不是指物理內存,而是指虛擬內存大小,這個虛擬內存大小取決於磁碟交換區設定的大小。由程序申請的一塊內存,如果沒有任何一個指針指向它,那麼這塊內存就泄漏了。

⑵ 如何排查Java內存泄露

  • 1.打開/tomcat_home/bin/catalina.bat文件

    2.加上:set JAVA_OPTS=%JAVA_OPTS% -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:heapmp,這樣當內存溢出是就會在對應路徑下生成mp文件

⑶ 怎麼排查這些內存泄漏

最原始的內存泄露測試
重復多次操作關鍵的可疑的路徑,從內存監控工具中觀察內存曲線,是否存在不斷上升的趨勢且不會在程序返回時明顯回落。
這種方式可以發現最基本,也是最明顯的內存泄露問題,對用戶價值最大,操作難度小,性價比極高。
MAT內存分析工具
2.1 MAT分析heap的總內存佔用大小來初步判斷是否存在泄露
在Devices 中,點擊要監控的程序。
點擊Devices視圖界面中最上方一排圖標中的「Update Heap」
點擊Heap視圖
點擊Heap視圖中的「Cause GC」按鈕
到此為止需檢測的進程就可以被監視。Heap視圖中部有一個Type叫做data object,即數據對象,也就是我們的程序中大量存在的類類型的對象。在data object一行中有一列是「Total Size」,其值就是當前進程中所有Java數據對象的內存總量,一般情況下,這個值的大小決定了是否會有內存泄漏。可以這樣判斷:
進入某應用,不斷的操作該應用,同時注意觀察data object的Total Size值,正常情況下Total Size值都會穩定在一個有限的范圍內,也就是說由於程序中的的代碼良好,沒有造成對象不被垃圾回收的情況。
所以說雖然我們不斷的操作會不斷的生成很多對象,而在虛擬機不斷的進行GC的過程中,這些對象都被回收了,內存佔用量會會落到一個穩定的水平;反之如果代碼中存在沒有釋放對象引用的情況,則data object的Total Size值在每次GC後不會有明顯的回落。隨著操作次數的增多Total Size的值會越來越大,直到到達一個上限後導致進程被殺掉。
2.2 MAT分析hprof來定位內存泄露的原因所在。
這是出現內存泄露後使用MAT進行問題定位的有效手段。
A)Dump出內存泄露當時的內存鏡像hprof,分析懷疑泄露的類:

B)分析持有此類對象引用的外部對象

C)分析這些持有引用的對象的GC路徑

D)逐個分析每個對象的GC路徑是否正常

從這個路徑可以看出是一個antiRadiationUtil工具類對象持有了MainActivity的引用導致MainActivity無法釋放。此時就要進入代碼分析此時antiRadiationUtil的引用持有是否合理(如果antiRadiationUtil持有了MainActivity的context導致節目退出後MainActivity無法銷毀,那一般都屬於內存泄露了)。
2.3 MAT對比操作前後的hprof來定位內存泄露的根因所在。
為查找內存泄漏,通常需要兩個 Dump結果作對比,打開 Navigator History面板,將兩個表的 Histogram結果都添加到 Compare Basket中去
A) 第一個HPROF 文件(usingFile > Open Heap Dump ).
B)打開Histogram view.
C)在NavigationHistory view里 (如果看不到就從Window >show view>MAT- Navigation History ), 右擊histogram然後選擇Add to Compare Basket .

D)打開第二個HPROF 文件然後重做步驟2和3.
E)切換到Compare Basket view, 然後點擊Compare the Results (視圖右上角的紅色」!」圖標)。

F)分析對比結果

可以看出兩個hprof的數據對象對比結果。
通過這種方式可以快速定位到操作前後所持有的對象增量,從而進一步定位出當前操作導致內存泄露的具體原因是泄露了什麼數據對象。
注意:
如果是用 MAT Eclipse 插件獲取的 Dump文件,不需要經過轉換則可在MAT中打開,Adt會自動進行轉換。
而手機SDk Dump 出的文件要經過轉換才能被 MAT識別,Android SDK提供了這個工具 hprof-conv (位於 sdk/tools下)
首先,要通過控制台進入到你的 android sdk tools 目錄下執行以下命令:
./hprof-conv xxx-a.hprof xxx-b.hprof
例如 hprof-conv input.hprof out.hprof
此時才能將out.hprof放在eclipse的MAT中打開。
手機管家內存泄露每日監控方案
目前手機管家的內存泄露每日監控會自動運行並輸出是否存在疑似泄露的報告郵件,不論泄露對象的大小。這其中涉及的核心技術主要是AspectJ,MLD自研工具(原理是虛引用)和UIAutomator。
3.1 AspectJ插樁監控代碼
手機管家目前使用一個ant腳本加入MLD的監控代碼,並通過AspectJ的語法實現插樁。
使用AspectJ的原因是可以靈活分離出項目源碼與監控代碼,通過不同的編譯腳本打包出不同用途的安裝測試包:如果測試包是經過Aspect插樁了MLD監控代碼的話,那麼運行完畢後會輸出指定格式的日誌文件,作為後續分析工作的數據基礎。
3.2 MLD實現監控核心邏輯
這是手機管家內的一個工具工程,正式打包不會打入,BVT等每日監控測試包可以打入。打入後可以通過諸如addObject介面(通過反射去檢查是否含有該工具並調用)來加入需要監控的檢測對象,這個工具會自動在指定時機(如退出管家)去檢測該對象是否發生泄漏。
這個內存泄露檢測的基本原理是:
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用必須和引用隊列(ReferenceQueue)聯合使用(在虛引用函數就必須關聯指定)。當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,自動把這個虛引用加入到與之關聯的引用隊列中。程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。
基於以上原理,MLD工具在調用介面addObject加入監控類型時,會為該類型對象增加一個虛引用,注意虛引用並不會影響該對象被正常回收。因此可以在ReferenceQueue引用隊列中統計未被回收的監控對象是否超過指定閥值。
利用PhantomReferences(虛引用)和ReferenceQueue(引用隊列),當PhantomReferences被加入到相關聯的ReferenceQueue時,則視該對象已經或處於垃圾回收器回收階段了。

MLD監控原理核心
目前手機管家已對大部分類完成內存泄露的監控,包括各種activity,service和view頁面等,務求在技術上能帶給用戶最順滑的產品體驗。
接下來簡單介紹下這個工具的判斷核心。根據虛引用監控到的內存狀態,需要通過多種策略來判斷是否存在內存泄露。
(1)最簡單的方式就是直接在加入監控時就為該類型設定最大存在個數,舉個例子,各個DAO對象理論上只能存在最多一個,因此一旦出現兩個相同的DAO,那一般都是泄露了;
(2)第二種情況是在頁面退出程序退出時,檢索gc後無法釋放的對象列表,這些對象類型也會成為內存泄露的懷疑對象;
(3)最後一種情況比較復雜,基本原理是根據歷史操作判斷對象數量的增長幅度。根據對象的增長通過最小二乘法擬合出該對象類型的增長速度,如果超過經驗值則會列入疑似泄露的對象列表。
3.3 UIAutomator完成重復操作的自動化
最後一步就很簡單了。這么多反復的UI操作,讓人工來點就太浪費人力了。我們使用UIAutomator來進行自動化操作測試。
目前手機管家的每日自動化測試已覆蓋各個功能的主路徑,並通過配置文件的方式來靈活驅動用例的增刪改查,最大限度保證了隨著版本推移用例的復用價值。
至此手機管家的內存泄露測試方案介紹完畢,也歡迎各路牛人交流溝通更多更強的內存泄露工具盒方案!
騰訊Bugly簡介
Bugly是騰訊內部產品質量監控平台的外發版本,其主要功能是App發布以後,對用戶側發生的Crash以及卡頓現象進行監控並上報,讓開發同學可以第一時間了解到App的質量情況,及時機型修改。目前騰訊內部所有的產品,均在使用其進行線上產品的崩潰監控。

⑷ 系統測試中怎麼確定內存泄露

是不是說沒有一種內存檢查工具能夠在linux使用呢,也不是,像valgrind工具還是相當不錯的。他的下載地址是下載一個valgrind3.2.3(tar.bz2)工具,按照裡面的README提示,安裝後就可以使用這個工具來檢測內存泄露和內存越界等。這是一個沒有界面的內存檢測工具,安裝後,輸入valgrindls-l驗證一下該工具是否工作正常(這是README裡面的方法,實際上是驗證一下對ls-l命令的內存檢測),如果你看到一堆的信息說明你的工具可以使用了。在編譯你的程序時,請設置-g參數,編譯出後使用如下的命令來判斷你的程序存在內存泄露:valgrind--tools=memcheck--leak-check=fullyourProg在輸出信息中就會看到你的內存問題了。

⑸ 如何檢查內存泄露問題

我在實現過程中,也有點拿不穩,特別是用隊列或棧來存儲樹的結點(也是指針)時,為了確保沒問題,特別是內存的分配,我搜索並安裝了Virtual Leak Detector,一個開源的內存泄漏檢測工具。
初識Visual Leak Detector
靈活自由是C/C++語言的一大特色,而這也為C/C++程 序員出了一個難題。當程序越來越復雜時,內存的管理也會變得越加復雜,稍有不慎就會出現內存問題。內存泄漏是最常見的內存問題之一。內存泄漏如果不是很嚴 重,在短時間內對程序不會有太大的影響,這也使得內存泄漏問題有很強的隱蔽性,不容易被發現。然而不管內存泄漏多麼輕微,當程序長時間運行時,其破壞力是 驚人的,從性能下降到內存耗盡,甚至會影響到其他程序的正常運行。另外內存問題的一個共同特點是,內存問題本身並不會有很明顯的現象,當有異常現象出現時 已時過境遷,其現場已非出現問題時的現場了,這給調試內存問題帶來了很大的難度。< xmlnamespace prefix ="o" />

Visual Leak Detector是一款用於Visual C++的免費的內存泄露檢測工具。可以在http://www.codeproject.com/tools/visualleakdetector.asp 下載到。相比較其它的內存泄露檢測工具,它在檢測到內存泄漏的同時,還具有如下特點:
1、 可以得到內存泄漏點的調用堆棧,如果可以的話,還可以得到其所在文件及行號;
2、 可以得到泄露內存的完整數據;
3、 可以設置內存泄露報告的級別;
4、 它是一個已經打包的lib,使用時無須編譯它的源代碼。而對於使用者自己的代碼,也只需要做很小的改動;
5、 他的源代碼使用GNU許可發布,並有詳盡的文檔及注釋。對於想深入了解堆內存管理的讀者,是一個不錯的選擇。

可見,從使用角度來講,Visual Leak Detector簡單易用,對於使用者自己的代碼,唯一的修改是#include Visual Leak Detector的頭文件後正常運行自己的程序,就可以發現內存問題。從研究的角度來講,如果深入Visual Leak Detector源代碼,可以學習到堆內存分配與釋放的原理、內存泄漏檢測的原理及內存操作的常用技巧等。
本文首先將介紹Visual Leak Detector的使用方法與步驟,然後再和讀者一起初步的研究Visual Leak Detector的源代碼,去了解Visual Leak Detector的工作原理。
< xmlnamespace prefix ="v" />
使用Visual Leak Detector(1.0)
下面讓我們來介紹如何使用這個小巧的工具。
首先從網站上下載zip包,解壓之後得到vld.h, vldapi.h, vld.lib, vldmt.lib, vldmtdll.lib, dbghelp.dll等文件。將.h文件拷貝到Visual C++的默認include目錄下,將.lib文件拷貝到Visual C++的默認lib目錄下,便安裝完成了。因為版本問題,如果使用windows 2000或者以前的版本,需要將dbghelp.dll拷貝到你的程序的運行目錄下,或其他可以引用到的目錄。
註:我下載的是較新版1.9,直接安裝到系統中。因此使用時必須先在VC中設置一下目錄。

接下來需要將其加入到自己的代碼中。方法很簡單,只要在包含入口函數的.cpp文件中包含vld.h就可以。如果這個cpp文件包含了stdafx.h,則將包含vld.h的語句放在stdafx.h的包含語句之後,否則放在最前面。如下是一個示常式序:
#include <vld.h>
void main()
{

}
接下來讓我們來演示如何使用Visual Leak Detector檢測內存泄漏。下面是一個簡單的程序,用new分配了一個int大小的堆內存,並沒有釋放。其申請的內存地址用printf輸出到屏幕上。

編譯運行後,在標准輸出窗口得到:
p=003a89c0

在Visual C++的Output窗口得到:

WARNING: Visual Leak Detector detected memory leaks!
---------- Block 57 at 0x003A89C0: 4 bytes ---------- --57號塊0x003A89C0地址泄漏了4個位元組
Call Stack: --下面是調用堆棧
d:/test/testvldconsole/testvldconsole/main.cpp (7): f --表示在main.cpp第7行的f()函數
d:/test/testvldconsole/testvldconsole/main.cpp (14): main –雙擊以引導至對應代碼處
f:/rtm/vctools/crt_bld/self_x86/crt/src/crtexe.c (586): __tmainCRTStartup
f:/rtm/vctools/crt_bld/self_x86/crt/src/crtexe.c (403): mainCRTStartup
0x7C816D4F (File and line number not available): RegisterWaitForInputIdle
Data: --這是泄漏內存的內容,0x12345678
78 56 34 12 xV4..... ........

Visual Leak Detector detected 1 memory leak.
第二行表示57號塊有4位元組的內存泄漏,地址為0x003A89C0,根據程序控制台的輸出,可以知道,該地址為指針p。程序的第7行,f()函數里,在該地址處分配了4位元組的堆內存空間,並賦值為0x12345678,這樣在報告中,我們看到了這4位元組同樣的內容。
可以看出,對於每一個內存泄漏,這個報告列出了它的泄漏點、長度、分配該內存時的調用堆棧、和泄露內存的內容(分別以16進制和文本格式列出)。雙擊該堆棧報告的某一行,會自動在代碼編輯器中跳到其所指文件的對應行。這些信息對於我們查找內存泄露將有很大的幫助。
這是一個很方便易用的工具,安裝後每次使用時,僅僅需要將它頭文件包含進來重新build就可以。而且,該工具僅在build Debug版的時候會連接到你的程序中,如果build Release版,該工具不會對你的程序產生任何性能等方面影響。所以盡可以將其頭文件一直包含在你的源代碼中。
Visual Leak Detector工作原理
下面讓我們來看一下該工具的工作原理。
在這之前,我們先來看一下Visual C++內置的內存泄漏檢測工具是如何工作的。Visual C++內置的工具CRT Debug Heap工作原來很簡單。在使用Debug版的malloc分配內存時,malloc會在內存塊的頭中記錄分配該內存的文件名及行號。當程序退出時CRT會在main()函數返回之後做一些清理工作,這個時候來檢查調試堆內存,如果仍然有內存沒有被釋放,則一定是存在內存泄漏。從這些沒有被釋放的內存塊的頭中,就可以獲得文件名及行號。
這種靜態的方法可以檢測出內存泄漏及其泄漏點的文件名和行號,但是並不知道泄漏究竟是如何發生的,並不知道該內存分配語句是如何被執行到的。要想了解這些,就必須要對程序的內存分配過程進行動態跟蹤。Visual Leak Detector就是這樣做的。它在每次內存分配時將其上下文記錄下來,當程序退出時,對於檢測到的內存泄漏,查找其記錄下來的上下文信息,並將其轉換成報告輸出。

初始化
Visual Leak Detector要記錄每一次的內存分配,而它是如何監視內存分配的呢?Windows提供了分配鉤子(allocation hooks)來監視調試堆內存的分配。它是一個用戶定義的回調函數,在每次從調試堆分配內存之前被調用。在初始化時,Visual Leak Detector使用_CrtSetAllocHook注冊這個鉤子函數,這樣就可以監視從此之後所有的堆內存分配了。
如何保證在Visual Leak Detector初始化之前沒有堆內存分配呢?全局變數是在程序啟動時就初始化的,如果將Visual Leak Detector作為一個全局變數,就可以隨程序一起啟動。但是C/C++並沒有約定全局變數之間的初始化順序,如果其它全局變數的構造函數中有堆內存分配,則可能無法檢測到。Visual Leak Detector使用了C/C++提供的#pragma init_seg來在某種程度上減少其它全局變數在其之前初始化的概率。根據#pragma init_seg的定義,全局變數的初始化分三個階段:首先是compiler段,一般c語言的運行時庫在這個時候初始化;然後是lib段,一般用於第三方的類庫的初始化等;最後是user段,大部分的初始化都在這個階段進行。Visual Leak Detector將其初始化設置在compiler段,從而使得它在絕大多數全局變數和幾乎所有的用戶定義的全局變數之前初始化。

記錄內存分配
一個分配鉤子函數需要具有如下的形式:
int YourAllocHook( int allocType, void *userData, size_t size, int blockType, long requestNumber, const unsignedchar *filename, int lineNumber);
就像前面說的,它在Visual Leak Detector初始化時被注冊,每次從調試堆分配內存之前被調用。這個函數需要處理的事情是記錄下此時的調用堆棧和此次堆內存分配的唯一標識——requestNumber。
得到當前的堆棧的二進製表示並不是一件很復雜的事情,但是因為不同體系結構、不同編譯器、不同的函數調用約定所產生的堆棧內容略有不同,要解釋堆棧並得到整個函數調用過程略顯復雜。不過windows提供一個StackWalk64函數,可以獲得堆棧的內容。StackWalk64的聲明如下:
BOOL StackWalk64(
DWORD MachineType,
HANDLE hProcess,
HANDLE hThread,
LPSTACKFRAME64 StackFrame,
PVOID ContextRecord,
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
PGET_MODULE_BASE_ROUTINE64 GetMoleBaseRoutine,
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
);

STACKFRAME64結構表示了堆棧中的一個frame。給出初始的STACKFRAME64,反復調用該函數,便可以得到內存分配點的調用堆棧了。
// Walk the stack.
while (count < _VLD_maxtraceframes) {
count++;
if (!pStackWalk64(architecture, m_process, m_thread, &frame, &context,
NULL, pSymFunctionTableAccess64, pSymGetMoleBase64, NULL)) {
// Couldn't trace back through any more frames.
break;
}
if (frame.AddrFrame.Offset == 0) {
// End of stack.
break;
}

// Push this frame's program counter onto the provided CallStack.
callstack->push_back((DWORD_PTR)frame.AddrPC.Offset);
}
那麼,如何得到初始的STACKFRAME64結構呢?在STACKFRAME64結構中,其他的信息都比較容易獲得,而當前的程序計數器(EIP)在x86體系結構中無法通過軟體的方法直接讀取。Visual Leak Detector使用了一種方法來獲得當前的程序計數器。首先,它調用一個函數,則這個函數的返回地址就是當前的程序計數器,而函數的返回地址可以很容易的從堆棧中拿到。下面是Visual Leak Detector獲得當前程序計數器的程序:
#if defined(_M_IX86) || defined(_M_X64)
#pragma auto_inline(off)
DWORD_PTR VisualLeakDetector::getprogramcounterx86x64 ()
{
DWORD_PTR programcounter;

__asm mov AXREG, [BPREG + SIZEOFPTR] // Get the return address out of the current stack frame
__asm mov [programcounter], AXREG // Put the return address into the variable we'll return

return programcounter;
}
#pragma auto_inline(on)
#endif // defined(_M_IX86) || defined(_M_X64)
得到了調用堆棧,自然要記錄下來。Visual Leak Detector使用一個類似map的數據結構來記錄該信息。這樣可以方便的從requestNumber查找到其調用堆棧。分配鉤子函數的allocType參數表示此次堆內存分配的類型,包括_HOOK_ALLOC, _HOOK_REALLOC, 和 _HOOK_FREE,下面代碼是Visual Leak Detector對各種情況的處理。

switch (type) {
case _HOOK_ALLOC:
visualleakdetector.hookmalloc(request);
break;

case _HOOK_FREE:
visualleakdetector.hookfree(pdata);
break;

case _HOOK_REALLOC:
visualleakdetector.hookrealloc(pdata, request);
break;

default:
visualleakdetector.report("WARNING: Visual Leak Detector: in allochook(): Unhandled allocation type (%d)./n", type);
break;
}
這里,hookmalloc()函數得到當前堆棧,並將當前堆棧與requestNumber加入到類似map的數據結構中。hookfree()函數從類似map的數據結構中刪除該信息。hookrealloc()函數依次調用了hookfree()和hookmalloc()。

檢測內存泄露
前面提到了Visual C++內置的內存泄漏檢測工具的工作原理。與該原理相同,因為全局變數以構造的相反順序析構,在Visual Leak Detector析構時,幾乎所有的其他變數都已經析構,此時如果仍然有未釋放之堆內存,則必為內存泄漏。
分配的堆內存是通過一個鏈表來組織的,檢查內存泄漏則是檢查此鏈表。但是windows沒有提供方法來訪問這個鏈表。Visual Leak Detector使用了一個小技巧來得到它。首先在堆上申請一塊臨時內存,則該內存的地址可以轉換成指向一個_CrtMemBlockHeader結構,在此結構中就可以獲得這個鏈表。代碼如下:
char *pheap = new char;
_CrtMemBlockHeader *pheader = pHdr(pheap)->pBlockHeaderNext;
delete pheap;
其中pheader則為鏈表首指針。

報告生成
前面講了Visual Leak Detector如何檢測、記錄內存泄漏及其其調用堆棧。但是如果要這個信息對程序員有用的話,必須轉換成可讀的形式。Visual Leak Detector使用SymGetLineFromAddr64()及SymFromAddr()生成可讀的報告。
// Iterate through each frame in the call stack.
for (frame = 0; frame < callstack->size(); frame++) {
// Try to get the source file and line number associated with
// this program counter address.
if (pSymGetLineFromAddr64(m_process,
(*callstack)[frame], &displacement, &sourceinfo)) {
...
}

// Try to get the name of the function containing this program
// counter address.
if (pSymFromAddr(m_process, (*callstack)[frame],
&displacement64, pfunctioninfo)) {
functionname = pfunctioninfo->Name;
}
else {
functionname = "(Function name unavailable)";
}
...
}
概括講來,Visual Leak Detector的工作分為3步,首先在初始化注冊一個鉤子函數;然後在內存分配時該鉤子函數被調用以記錄下當時的現場;最後檢查堆內存分配鏈表以確定是否存在內存泄漏並將泄漏內存的現場轉換成可讀的形式輸出。有興趣的讀者可以閱讀Visual Leak Detector的源代碼。

總結
在使用上,Visual Leak Detector簡單方便,結果報告一目瞭然。在原理上,Visual Leak Detector針 對內存泄漏問題的特點,可謂對症下葯——內存泄漏不是不容易發現嗎?那就每次內存分配是都給記錄下來,程序退出時算總賬;內存泄漏現象出現時不是已時過境 遷,並非當時泄漏點的現場了嗎?那就把現場也記錄下來,清清楚楚的告訴使用者那塊泄漏的內存就是在如何一個調用過程中泄漏掉的。
Visual Leak Detector是一個簡單易用內存泄漏檢測工具。現在最新的版本是1.9a,採用了新的檢測機制,並在功能上有了很多改進。不妨體驗一下

⑹ 如何判斷內存泄漏

內存泄露是指使用內存完成後沒有釋放,內存增長並不能分辨增長出來的內存是進程真正要用的,還是進程泄露出來的。而CPU的佔用是瞬時的、確定的,不存在某個進程申請了CPU占著不用的情況。在穩定性測試(也叫持久測試或疲勞測試)中,需要觀察內存是否有泄露。然而使用內存的進程千千萬,整個伺服器的內存增長似乎也不能判斷某個進程的內存有泄露。因此在穩定性測試過程中往往需要全程關注指定進程的內存消耗,比如運行3天、7天。

查看內存使用情況的命令有ps、sar、svmon、vmstat等等,但本文並不從工具使用的角度來介紹,而是從性能測試中關注指標的角度來介紹。如果採用其他命令查看內存,需注意,相似的名字在不同命令當中的含義是不一樣的,一定要搞清楚這個欄位的真正含義。

例1:Virtual這個詞,有時候在內存裡面指Paging Space(換頁空間),有時指進程空間裡面佔用的所有分頁(包括物理內存和Paging Space中的分頁)。

例2:Nmon中的PgIn/PgOut、topas中的PageIn/PageOut是指對文件系統的換頁,而vmstat中的pi/po是對Paging Space的換頁,而topas P中進程的PAGE SPACE是指進程的Data Segment。

⑺ 如何查找內存泄露

這兩天,在查找內存泄露的問題。因為內存都是放在memory pool里,所以不能通過valgrind等工具抓到那個地方分配的內存沒有手動被釋放。使用gcc,有一個方法去打包內存分配函數,而且不需要編輯已有的code並且不需要修改目標文件。linker ld 提供了一個內建的選項去替換函數符號。 –wrap(一個橫線) 表示把函數 func 替換為(兩個下劃線前綴)__wrap_func 。可以通過這個選項傳給gcc去做恰當的鏈接。舉個例子來說明吧。 如果最後的free函數被注釋掉,那麼p就會出現內存泄漏,如果calloc已經被打包把內存放到memory pool里,程序退出激活釋放memory pool的話。那麼在程序為退出之前,那些mem還是存在的,因此當前進程會暫用很多內存(如果很多分配沒有free的話) view plain to clipboard#include<iostream> using namespace std; int main() { int allocTimes = 100; while(allocTimes--) { int *p = (int*)calloc(5, sizeof(int)); //free(p); } } 怎樣來檢查這些分配沒釋放的內存呢。就可以使用上面說的,定義一些函數,然後通過編譯器傳給連接器去替換函數。把這些函數定義在一個文件中(test.h):view plain to clipboard#ifndef TEST_INC #define TEST_INC #include<iostream> using namespace std; #ifdef __cplusplus extern "C" { #endif extern void *__real_calloc(size_t nmemb, size_t size); extern void *__real_realloc(void *ptr, size_t size); extern void *__real_malloc(size_t size); extern void __real_free(void *ptr); void *__wrap_calloc(size_t numemb, size_t size); void *__wrap_realloc(void *ptr, size_t size); void *__wrap_malloc(size_t size); void __wrap_free(void *ptr); /* wrap calloc */ void * __wrap_calloc(size_t numemb, size_t size) { cout << "wrap alloc" << endl; return __real_calloc(numemb, size); } /* wrap realloc */ void * __wrap_realloc(void *ptr, size_t size) { cout << "wrap realloc" << endl; return (void*)__real_realloc(ptr, size); } /* wrap malloc */ void * __wrap_malloc(size_t size) { cout << "wrap malloc" << endl; return (void*)__real_malloc(size); } /* wrap malloc */ void __wrap_free(void *p) { cout << "wrap free" << endl; __real_free(p); } #ifdef __cplusplus }; /* end of extern "C" */ #endif #endif /* ----- #ifndef TEST_INC ----- */ .cpp只需要加上這個頭文件view plain to clipboard#include<iostream> using namespace std; <span style="color:#ff0000;">#include "test.h"</span> int main() { int allocTimes = 100; while(allocTimes--) { int *p = (int*)calloc(5, sizeof(int)); //free(p); } } 然後在Makefile加上編譯選項CFLAGS = -g -O0 -Wall -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc -Wl,--wrap,realloc 或者g++ test.cc -o test -g -O0 -Wall -Wl,--wrap,calloc -Wl,--wrap,free -Wl,-wrap,malloc -Wl,-wrap,realloc 去編譯一個文件執行./test 即可發現alloc 和 free不匹配。此方法只是拋磚引玉。

⑻ 如何識別Java中的內存泄漏

1、內存泄漏的現象:
常常地,程序內存泄漏的最初跡象發生在出錯之後,在程序中得到一個OutOfMemoryError。這種典型的情況發生在產品環境中,而在那裡,希望內存泄漏盡可能的少,調試的可能性也達到最小。也許測試環境和產品的系統環境不盡相同,導致泄露的只會在產品中暴露。這種情況下,需要一個低負荷的工具來監聽和尋找內存泄漏。同時,還需要把這個工具同系統聯系起來,而不需要重新啟動他或者機械化代碼。也許更重要的是,當做分析的時候,需要能夠同工具分離而使得系統不會受到干擾。
一個OutOfMemoryError常常是內存泄漏的一個標志,有可能應用程序的確用了太多的內存;這個時候,既不能增加JVM的堆的數量,也不能改變程序而使得減少內存使用。但是,在大多數情況下,一個OutOfMemoryError是內存泄漏的標志。一個解決辦法就是繼續監聽GC的活動,看看隨時間的流逝,內存使用量是否會增加,如果有,程序中一定存在內存泄漏。
2. 發現內存泄漏
1. jstat -gc pid
可以顯示gc的信息,查看gc的次數,及時間。
其中最後五項,分別是young gc的次數,young gc的時間,full gc的次數,full gc的時間,gc的總時間。
2.jstat -gccapacity pid
可以顯示,VM內存中三代(young,old,perm)對象的使用和佔用大小,
如:PGCMN顯示的是最小perm的內存使用量,PGCMX顯示的是perm的內存最大使用量,
PGC是當前新生成的perm內存佔用量,PC是但前perm內存佔用量。
其他的可以根據這個類推, OC是old內純的佔用量。
3.jstat -gcutil pid
統計gc信息統計。
4.jstat -gcnew pid
年輕代對象的信息。
5.jstat -gcnewcapacity pid
年輕代對象的信息及其佔用量。
6.jstat -gcold pid
old代對象的信息。
7.stat -gcoldcapacity pid
old代對象的信息及其佔用量。
8.jstat -gcpermcapacity pid
perm對象的信息及其佔用量。
9.jstat -class pid
顯示載入class的數量,及所佔空間等信息。
10.jstat -compiler pid
顯示VM實時編譯的數量等信息。
11.stat -printcompilation pid
當前VM執行的信息。
一些術語的中文解釋:
S0C:年輕代中第一個survivor(倖存區)的容量 (位元組)
S1C:年輕代中第二個survivor(倖存區)的容量 (位元組)
S0U:年輕代中第一個survivor(倖存區)目前已使用空間 (位元組)
S1U:年輕代中第二個survivor(倖存區)目前已使用空間 (位元組)
EC:年輕代中Eden(伊甸園)的容量 (位元組)
EU:年輕代中Eden(伊甸園)目前已使用空間 (位元組)
OC:Old代的容量 (位元組)
OU:Old代目前已使用空間 (位元組)
PC:Perm(持久代)的容量 (位元組)
PU:Perm(持久代)目前已使用空間 (位元組)
YGC:從應用程序啟動到采樣時年輕代中gc次數
YGCT:從應用程序啟動到采樣時年輕代中gc所用時間(s)
FGC:從應用程序啟動到采樣時old代(全gc)gc次數
FGCT:從應用程序啟動到采樣時old代(全gc)gc所用時間(s)
GCT:從應用程序啟動到采樣時gc用的總時間(s)
NGCMN:年輕代(young)中初始化(最小)的大小 (位元組)
NGCMX:年輕代(young)的最大容量 (位元組)
NGC:年輕代(young)中當前的容量 (位元組)
OGCMN:old代中初始化(最小)的大小 (位元組)
OGCMX:old代的最大容量 (位元組)
OGC:old代當前新生成的容量 (位元組)
PGCMN:perm代中初始化(最小)的大小 (位元組)
PGCMX:perm代的最大容量 (位元組)
PGC:perm代當前新生成的容量 (位元組)
S0:年輕代中第一個survivor(倖存區)已使用的占當前容量百分比
S1:年輕代中第二個survivor(倖存區)已使用的占當前容量百分比
E:年輕代中Eden(伊甸園)已使用的占當前容量百分比
O:old代已使用的占當前容量百分比
P:perm代已使用的占當前容量百分比
S0CMX:年輕代中第一個survivor(倖存區)的最大容量 (位元組)
S1CMX :年輕代中第二個survivor(倖存區)的最大容量 (位元組)
ECMX:年輕代中Eden(伊甸園)的最大容量 (位元組)
DSS:當前需要survivor(倖存區)的容量 (位元組)(Eden區已滿)
TT:持有次數限制
MTT :最大持有次數限制

熱點內容
scratch少兒編程課程 發布:2025-04-16 17:11:44 瀏覽:640
榮耀x10從哪裡設置密碼 發布:2025-04-16 17:11:43 瀏覽:368
java從入門到精通視頻 發布:2025-04-16 17:11:43 瀏覽:86
php微信介面教程 發布:2025-04-16 17:07:30 瀏覽:310
android實現陰影 發布:2025-04-16 16:50:08 瀏覽:794
粉筆直播課緩存 發布:2025-04-16 16:31:21 瀏覽:346
機頂盒都有什麼配置 發布:2025-04-16 16:24:37 瀏覽:213
編寫手游反編譯都需要學習什麼 發布:2025-04-16 16:19:36 瀏覽:816
proteus編譯文件位置 發布:2025-04-16 16:18:44 瀏覽:367
土壓縮的本質 發布:2025-04-16 16:13:21 瀏覽:594