解決Solaris應用程序開發內存泄漏問題

作者: 李凌雲,張一峯(laoeyu)

 

 

內存泄漏是應用軟件開發過程中經常會遇到的問題,應用長期內存泄漏會佔用大量操作系統內存資源,直接導致應用程序運行不穩定,嚴重時甚至還會影響到操作系統的正常運行。爲了找到應用程序內存泄漏點,許多開發人員不得不在上千行乃至幾十萬行源程序中加入更多的調試代碼,試圖從調試信息中找到內存泄漏的根源,但通常來講這種方法是事倍功半的。幸運的是,Solaris平臺提供了好幾個實用的工具,能夠輔助開發人員對內存泄漏根源進行定位。筆者參考了 Sun公司官方網站上相關的英文技術文檔,並認爲這些對於我們中國廣大的Sun技術愛好者有很好的指導作用。筆者經過消化整理後寫下此文希望與大家共享。在下面的章節 中將初步講述如何在Solaris 10操作系統下利用這些工具查找用戶程序的內存泄漏點。文章各節標題如下:

1. 概述
2. 內存泄漏及危害
3. dbx
4. libumem
5. DTrace
6. libgc
7.
總結
8.
參考資料

 

內存泄漏及危害

如果要給內存泄漏下個定義的話,它應該屬於軟件程序設計的一種缺陷,該缺陷直接導致了程序在運行過程中無法釋放不再需要的內存空間,從而造成內存資源浪費。具體來說,當用戶程序在運行過程中需要動態獲得內存時,操作系統總是從堆(heap)上分配相應的空間給應用,分配的結果是將該堆內存的起始地址通過指針返回給應用。正常情況下,應用使用完這塊內存後,應通過系統調用主動通知操作系統回收這些堆內存以便重用。但是,如果由於設計缺陷導致在某些情況下程序沒有主動地通知到操作系統,而後應用又失去了對這塊內存的引用時,則該堆內存塊將成爲既不受程序控制,又不能被系統回收重用的"孤兒"內存,這便是我們所指的內存泄漏。

造成內存泄漏的設計缺陷多種多樣,下面例舉了部分典型的內存泄漏設計缺陷,它們都是開發人員經常會犯的毛病。

一個原先運行正常的系統由於安裝運行了用戶應用程序後經常發生以下任意症狀時,則應用程序有可能存在內存泄漏問題:

  • 沒有特殊原因,應用程序經長時間運行後所佔虛擬內存總量仍在持續性地不斷增長(即使增長過程十分緩慢)。通過使用prstat可以查詢進程內存使用情況。

  • swap設備配置和運行正常,且沒有大文件佔用/tmp目錄的情況下,經常有進程報告"Out of Memory"錯誤。通過使用swap -s命令可以查詢swap空間使用情況,以及使用df -k查詢/tmp的使用情況。

一個有內存泄漏問題的應用程序經過長時間運行後,通常會逐漸佔用大量操作系統內存。操作系統會因內存短缺而造成整體性能下降,嚴重時可以造成系統中其他真正需要內存的進程因得不到內存空間而無法正常運行,操作系統也會由於內存耗盡而變得不穩定。在下面的章節中,我們將介紹在Solaris 10平臺上有哪些工具幫助我們分析內存泄漏問題。

dbx

Sun StudioSun公司推出的面向CC++Fortran語言編程的開發環境,目前最新版本是Sun Studio 11。它包括一個非常友好而專業的GUI集成開發環境,以及像dbxPerformance Analyzer等優秀的輔助工具。其中,dbx工具除了可以幫助開發人員進行源代碼級別的跟蹤調試以外,它還可以幫助開發人員查找和定位應用程序中內存泄漏的問題。令人興奮的是,Sun Studio 11不像以前各版本那樣需要購買License,它是免費下載和使用的(包括商用),有興趣的話可以到http://developers.sun.com/prodtech/cc/downloads/index.jsp下載。

Runtime Checking

dbx中提供內存泄漏檢查功能的模塊被稱爲RTC,即Runtime Checking。它除了提供內存泄漏檢查功能外,還可以進行內存訪問檢查和使用檢查,對於發現程序中內存越界訪問或者變量未初始化就訪問等編程問題很有幫助。缺省情況下,dbx不啓用內存泄漏檢查功能,用戶可以通過check -leaks命令啓用它。check -leaks是一個反覆切換開關,在已經啓用內存泄漏檢查功能的情況下再使用該命令可以關閉這個功能。使用內存泄漏檢查功能不需要對程序進行重編譯,它也支持在優化過的目標代碼中查找內存泄漏。

使用RTC模塊有一些前提要求,比如:

  • 程序必須是由Sun提供的編譯器所編譯生成的;

  • 程序使用動態庫方式鏈接libc庫;

  • 內存是通過libc庫的malloc()free()realloc()或其他基於這些調用的函數進行申請和管理的;

  • 程序不能被完全strip,即符號表必須存在。strip -x命令仍可以接受。

RTC還有部分限制,比如:

  • 只能在Solaris操作系統上使用;

  • 在基於非UltraSPARC芯片的主機系統上使用時,程序的text段和數據data段不能超過8MB空間。

RTC對於內存泄漏分三種情況:

  • Memory Leak(mel),即進程中不存在任何一個指針指向某內存塊,則該內存塊爲真正的內存泄漏塊。

  • Address in Block(aib),即進程中不存在任何一個指針指向某內存塊的啓始位置,卻存在指向該內存塊中間某位置的指針。這是一個可疑的內存泄漏,即它很可能會演變爲Memroy Leak,但也不排除程序設計者爲了某種需要故意設計成這樣的。
  • Address in Register(air),即進程代碼段及數據段中沒有任何一個指針指向該內存塊,但在至少一個寄存器中存在相關的指針。這是一個可疑的內存泄漏。如果程序在編譯時使用了優化選項,比如-O等,則編譯器有可能只將內存指針保留於寄存器中,否則這會演變爲真正的內存泄漏。

dbx在報告內存泄漏時會區分上述三種情況,對於可能的內存泄漏,開發人員需要自行判斷是否爲真正的內存泄漏。

用dbx查內存泄漏

使用dbx檢查內存泄漏是所有工具中最方便的。如果程序在編譯時使用了-g選項,dbx可以很方便地將內存泄漏點定位到源程序代碼行。使用dbx檢查內存泄漏的典型過程如下:

1. 使用dbx啓動被跟蹤的程序。

2. 用check -leaks打開內存泄漏檢查開關。

3. 運行程序直至結束。當程序運行結束時,dbx會給出類似以下的內存泄漏報告。


例子中報告了兩個內存泄漏,分別爲從main()過程調用到memory_leak()過程時有1次32字節的內存泄漏,以及從main()過程調用到address_in_register()過程時有1 次11字節的內存泄漏。爲了得到具體的源代碼行號,可以在運行程序前使用以下的命令將內存泄漏報告模式改爲verbose,然後重新運行程序。


例子中報告了內存泄漏點分別在源代碼第8行和第35行。

如果要檢查一個守護進程類型的服務程序是否發生內存泄漏,上述方法就不適用了,這是因爲守護進程永遠不會運行結束。對此,dbx提供了一個showleaks的命令可以讓開發人員在任何時候查看進程內存泄漏情況。另外,守護進程一般會多次進行fork(),所以也不適合採用dbx直接進行啓動。因此,對於守護進程類程序,開發人員可以通過以下方法啓動,然後dbx動態掛接到已運行的進程上再進行內存泄漏檢查。

1. 設定環境變量,預裝librtc.so

缺省情況下在程序啓動時librtc.so不會預裝入系統。這意味着即使後來dbx動態掛接上該進程後,也無法使用RTC功能。但開發人員可以通過設定LD_AUDIT環境變量,指定應用程序啓動時系統預裝入librtc.so。方法是:對於32位應用,將LD_AUDIT指向安裝目錄>/lib/下的rtcaudit.so,對於SPARC 64位應用,須指向lib/v9下的rtcaudit.so,對於AMD 64位應用,則爲lib/amd64/下rtcaudit.so

2. 啓動守護程序,並得到進程號。注意,啓動應用後應及時使用unset命令去除LD_AUDIT設置。後繼命令不應使用LD_AUDIT

3. 令dbx動態掛接上守護進程,關閉同步跟蹤,並打開內存泄漏檢查。可根據需要在程序合適的位置設好斷點,然後繼續執行程序或單步跟蹤執行程序。在必要的時候利用showleaks檢查內存泄漏情況。

其中,showleaks命令缺省只報告自上次報告內存泄漏後新發現的內存泄漏。如果使用-a選項,則showleaks報告所有內存泄漏。-v選項是指verbose模式,可以給出更詳細的報告。跟蹤完成後,可使用quit命令退出dbx

libumem

libumem的由來是原自SunOS 5.4中的Kernel Slab Allocator。爲了加速系統虛擬內存操作,Sun的工程師發明了Kernel Slab Allocator,後來也被推廣到Linux操作系統。Kernel Slab Allocator通過一種object cacheing技術策略來實現高效內存的處理。在實際使用中,這種Kernel Slab Allocator內存分配器被證明非常高效,在多顆CPU上,擴展性(Scability)表現亦極佳。由於Kernel Slab Allocator是工作在kernel狀態,所以相應地產生了一個在用戶空間工作的內存分配器: libumem。自Solaris 9update3)開始,Solaris就自帶這個全新的內存分配器: libumem

libumem不僅能夠優化程序的內存分配,而且還提供內存分配調試,記錄功能,配合mdb工具我們可以輕鬆觀察程序內存的分配情況和內存泄漏。在使用libumem檢測內存泄漏的問題的之前,我們必須瞭解一些在調試中libumem提供給我們信息的內存結構。

libumem工作內存結構

libumem也是使用Slab概念。SlabSlab Allocator中一個基本內存單元:Slab是代表一個或者多個虛擬內存中的頁(Page),它通常會被分割成爲多個大小等同的Chunks,被成爲BufferBuffer含有用戶所使用的數據,還會有一些額外的信息,不過這個取決環境變量的設置。這些額外的信息對我們調試,檢測內存泄漏非常有用。下面就是Buffer的一個基本結構:

Buffer結構中第一個sectionMetadata,主要提供內存分配的長度信息,我們這裏不使用,在32位程序應用中它是8個字節。Metadata後面是存儲用戶數據的User data Section。接着是Redzone部分,Redzone也是8個字節。最後是Debug Metadata也是8個字節。其中前四個字節代表一個指針,指向一個umem_bufctl_audit結構,這個結構記錄着內存分配時候的堆棧。該結構的定義可以在/usr/include/umem_impl.h找到。後面四個字節是校驗位,可以用來和前面字節一起來判斷這個buffer有沒有被破壞。

libumem使用方法

1. 預加載(Preload) libumem

如果在程序中需要調試,尋找內存泄漏,需要預先加載(Preload) libumem,並且設置上環境變量:UMEM_DEBUG=defaultUMEM_LOGGING=transactionLD_PRELOAD=libumem.so.1

csh中設置的例子

bash中設置的例子

2. 運行程序,在程序運行時使用gcore命令對目標程序的進程生成core文件。

3. 使用mdb命令倒入core文件。

  • ::umem_status命令查看libumem的日誌功能是否打開。

  • ::findleaks命令查看是否有內存泄漏。

  • 內存泄漏地址$,該命令會將該地址的內容以umem_bufctl_audit的結構,並且會顯示內存泄漏的時候的用戶堆棧。

  • ::umalog命令查看每次內存分配的時間,地址,堆棧。

  • 內存地址::umem_verify可以查看內存是否被破壞,比如內存的越界操作。

  • 內存地址::umem_log可以按CPU,線程打印出內存分配記錄。

 




解決Solaris應用程序開發內存泄漏問題 (2) 收藏
作者:李凌雲, 張一峯(laoeyu)

DTrace
DTrace是一個動態監測工具,它是在Solaris 10系統中Sun公司推出 的一個全新工具。DTrace這個工具是一個內嵌在Solaris系統中的子系統,也就是說我們可以在生產 環境下直接使用。它帶有30000多個監測點 Probe)。通過這些監測點,可以動態的蒐集操作系統 和應用程序的運行的方式和狀態,幫助我們迅速找到問題的關鍵原因。如果這些檢測點沒有打開,是絕 對不會給系統帶來任何開銷,並且即使打開監測點,系統開銷也是微乎其微的。DTrace不 僅能夠起到監測的作用,而且可以動態修改系統和程序的行爲。所有 這些都有相應的安全考慮,只有具有指定權限(Privilege)纔可以使用相應的功能。

 

DTrace也可以幫助我們解決Memory Leak問題。下面給出一個內存泄漏的例子,看一下如何通過DTrace找到這個Memory Leak。如果大家對DTrace不 熟悉的話,可以參考一篇DTrace入門的文章:http://blog.gceclub.sun.com.cn/index.php?op=ViewArticle&articleId=516&blogId=4

#include
#include
#include
#include
class TestClass
{
public:
TestClass() {
cout << "no-argument" <}


TestClass(const char *name) {
cout << "arg = " << name << endl;
}
};

int main(int argc, char **argv)
{
TestClass *t;
TestClass *tt;
while (1) {
t = new TestClass();
t = new TestClass("Hello.");
tt = new TestClass("Goodbye.");
delete(t);
delete(tt);
sleep(1);
}
}

我們看到這段代碼定義了一個TestClass類, 這個類含有兩個構造函數,一個構造函數無參數,另一個構造函數帶有一個const char *類型的字符串參數。這段代碼的main函數有 一個while無限循環,在這個循環中,程序創建(new)三個對象,但只釋放(delete)了兩個對 象,造成內存泄漏。

這段程序雖然使用new和delete操作符,但我們知道最後還是使用libc庫中的malloc和free兩個函數實現內存分配和釋放的。對於用戶進程,DTrace提供了 特別的Provider,叫做pid Provider進行探測。pid Provider提供的監測點可以通過function函 數名制定,比如malloc函數,它的入口監測點是pid$1:libc:malloc:entry,它的返回監測點是pid$1:libc:malloc:return, 其中pid表示pid Provider,$1表示所要監測的進程號,它的值來自命令行第一個參數。除了malloc函數外,realloc和calloc函數也可以分配內存。爲此,我們準備了一段檢 測Memory Leak的腳本trace.d:

#!/usr/sbin/dtrace -s

pid$1:libc:malloc:entry
{
self->trace = 1;
self->size = arg0;
}
pid$1:libc:malloc:return
/self->trace == 1/
{
printf("Ptr=0x%p Size=%d", arg1, self->size);
ustack();
self->trace = 0;
self->size = 0;
}

pid$1:libc:realloc:entry
{
self->trace = 1;
self->size = arg1;
self->oldptr = arg0;
}
pid$1:libc:realloc:return
/self->trace == 1/
{
printf("Ptr=0x%p Oldptr=0x%p Size=%d", arg1, self->oldptr, self->size);
ustack();
self->trace = 0;
self->size = 0;
}

pid$1:libc:calloc:entry
{
self->trace = 1;
self->size = arg1;
}
pid$1:libc:calloc:return
/self->trace == 1/
{
printf("Ptr=0x%p Size=%d", arg1, self->size);
ustack();
self->trace = 0;
self->size = 0;
}

pid$1:libc:free:entry
{
printf("Ptr=0x%p ", arg0);
}

當 進程調用malloc函數且剛進入malloc函數時,pid$1:libc:malloc:entry入口監測點就被觸發,其中DTrace內建變量 arg0存放了malloc函數的第一個參數,即所要申請的內存字節數。它被保存在一個線程級的self->size變量中,供後面引用。pid$1:libc:malloc:return檢測 點會在malloc函數返回時被觸發,DTrace會執行printf函數和ustack 函數。printf函數將打印出arg1以及self->size。其中,arg1也是DTrace內建變量,pid$1:libc: malloc:return返回監測點的arg1表示malloc函數的返 回值,即所分配的內存起始地址,而先前保留在self->size變量中內存字節數將一起被打印。ustack函數會打印出用戶堆棧。與此類似,腳本對realloc函數和calloc函數的調用進入和返回都設置了監測點。在腳本最後是針對free函數的監測點,pid$1:libc: free:entry會在free函數調 用入口時觸發,執行printf函數,printf函數會打印出被釋放的內存地址arg0,也就是先前通過malloc、realloc和calloc函數所分配的內存地址。

我們執行前面編譯出來的C++程序,同 時用DTrace執行trace.d腳本,並指定待檢測的進程的進程號(Process ID)。

# dtrace -s ./trace.d `pgrep a.out`


CPU ID FUNCTION:NAME
0 46868 malloc:return Ptr=0x28fd0 Size=8
libc.so.1`malloc+0x6c
libCrun.so.1`__1c2n6FI_pv_+0x28
a.out`main+0xc
a.out`_start+0x108

0 46868 malloc:return Ptr=0x28fc0 Size=7
libc.so.1`malloc+0x6c
libc.so.1`strdup+0xc
a.out`__1cJTestClass2t5B6M_v_+0x1c
a.out`main+0x1c
a.out`_start+0x108

0 46868 malloc:return Ptr=0x28f50 Size=8
libc.so.1`malloc+0x6c
libCrun.so.1`__1c2n6FI_pv_+0x28
a.out`main+0x50
a.out`_start+0x108

0 46868 malloc:return Ptr=0x28fe0 Size=7
libc.so.1`malloc+0x6c
libc.so.1`strdup+0xc
a.out`__1cJTestClass2t5B6Mpkc_v_+0x14
a.out`main+0x68
a.out`_start+0x108

0 46868 malloc:return Ptr=0x28ff0 Size=8
libc.so.1`malloc+0x6c
libCrun.so.1`__1c2n6FI_pv_+0x28
a.out`main+0x9c
a.out`_start+0x108

0 46868 malloc:return Ptr=0x41458 Size=9
libc.so.1`malloc+0x6c
libc.so.1`strdup+0xc
a.out`__1cJTestClass2t5B6Mpkc_v_+0x14
a.out`main+0xb4
a.out`_start+0x108

0 46873 free:entry Ptr=0x28fe0
0 46873 free:entry Ptr=0x28f50
0 46873 free:entry Ptr=0x41458
0 46873 free:entry Ptr=0x28ff0
....
^C

由於測試C++程序是一段while循環,我們只需要看一段循環就可以了,所以在 一個循環輸出後通過Ctrl+C中止DTrace的檢測。通過這段輸出信 息我們不難發現程序總共調用了6次malloc和4次free,通過比對malloc和free所涉及的內存地址Ptr,不難發現只有Ptr=0x28fd0以及Ptr=0x28fc0這兩塊內存沒有調用free釋放。ustack()提供的調用棧揭示內存泄漏發生在a.out`main+0xc和a.out`__1cJTestClass2t5B6M_v_+0x1c兩處,這是函 數名與地址偏移量組成的調用棧信息。其中由於C++編譯器的mangling特性,修改了一些函數名字,造成無法識別,我們可以通 過C++編譯器提供的工具nm, gc++filt把這些名字demangle過來,也可以使用Sun Studio自帶的工具dem進行翻譯,比如:

# /opt/SUNWspro/bin/dem __1c2n6FI_pv_
__1c2n6FI_pv_ == void*operator new(unsigned)


# /opt/SUNWspro/bin/dem __1cJTestClass2t5B6M_v_
__1cJTestClass2t5B6M_v_ == TestClass::TestClass()

我們可以看到問題是出在調用new TestClass()那 個無參數的構造函數,於是我們就找到了哪部分代碼導致的內存泄漏。


使用上述方法查找內存泄漏點時最令人頭疼的事情莫過於人工匹配malloc和free涉及的內存地址。最好有個工具可以自動去除無內存泄漏的調用點,只留下內存泄漏的信息。以下的Perl腳本可以幫助我們自動匹配內存地址,只留下內存泄漏相關的信息。


# cat ./findleaks.pl
#!/usr/bin/perl

# findleaks.pl

use Data::Dumper;

my %hash = ();

while (<>) {
if ((/malloc:return Ptr=([^ ]*) Size=(.*)/) ||
(/calloc:return Ptr=([^ ]*) Size=(.*)/)) {
$hash{$1} = { size => $2 };
while (<>) {
last if /^$/;
$hash{$1}->{stack} .= $_;
}
}
elsif (/free:entry Ptr=([^ ]*)/) {
if (exists $hash{$1} and $hash{$1}) {
$hash{$1} = '';
}
}
elsif (/realloc:entry Ptr=([^ ]*) Oldptr=([^ ]*) Size=(.*)/) {
if ($1 eq $2) {
if (exists $hash{$1} and $hash{$1}) {
$hash{$1} = { size => $3 };
$hash{$1}->{stack} = '';
while (<>) {
last if /^$/;
$hash{$1}->{stack} .= $_;
}
}
} else {
$hash{$1} = '';
$hash{$2}= { size => $3 };
$hash{$2}->{stack} = '';
while (<>) {
last if /^$/;
$hash{$2}->{stack} .= $_;
}
}
}
}

foreach my $key (keys %hash) {
next if not $hash{$key}->{size};
print "Ptr=$key Size=", $hash{$key}->{size}, "n";
print $hash{$key}->{stack}, "n---------n";
}

使用方法是將trace.d的輸出重定向到一個臨時文件,然後將該臨時文件作爲findleaks.pl的輸入。findleaks.pl的輸出即爲與內存相關的調用。注意findleaks.pl應置爲可執行。執行結果如下:


# dtrace -s ./trace.d `pgrep a.out` > ./tmpfile
# ./findleaks.pl ./tmpfile
Ptr=0x29090 Size=8
libc.so.1`malloc+0x6c
libCrun.so.1`__1c2n6FI_pv_+0x28
CCtest`main+0xc
CCtest`_start+0x108
---------
Ptr=0x29060 Size=7
libc.so.1`malloc+0x6c
libc.so.1`strdup+0xc
CCtest`__1cJTestClass2t5B6M_v_+0x1c
CCtest`main+0x1c
CCtest`_start+0x108
---------
Ptr=0x29130 Size=8
libc.so.1`malloc+0x6c
libCrun.so.1`__1c2n6FI_pv_+0x28
CCtest`main+0xc
CCtest`_start+0x108
---------
Ptr=0x29000 Size=7
libc.so.1`malloc+0x6c
libc.so.1`strdup+0xc
CCtest`__1cJTestClass2t5B6M_v_+0x1c
CCtest`main+0x1c
CCtest`_start+0x108
---------
...

libgc
Solaris系統爲C/C++語言提供了垃圾收集庫:libgc,這個庫會自動負責內存管理包括分配和釋放。 雖然它不能夠找到哪段代碼導致內存泄 漏,但是可以幫助我們徹底解決內存泄漏問題。這個庫包含在Sun Studio,支持X86和SPARC。安裝了Sun Studio後,庫文件的位置在/opt/SUNWspro/lib/。

libgc對內存的管理是通過自有的一個高效內存分配器 (Memory Allocator),對所有堆(Heap)中分 配內存都會打上標誌,如果發現這些打上標誌的內存沒有被指針使用,它就會取消標誌,並釋放。libgc會 自動定期掃描,決定什麼時候回收這些取消標誌的內存。如果遇到沒有內存可分配的情況,它也會執行回收動作。

libgc使用方式有兩種:

Deployment Mode

功能:可以自動解決內存泄漏。由於使用自有的內存分配器, 避免了內存碎片,同時內存分配的操作也會更快。
使用方法非常簡單,不需要修改代碼,只需在link庫文件 的時候指定鏈接libgc。

Development Mode

功能:除了提供上面一種模式所有的功能外,還能夠解決Premature Free的問題。

Premature Free是指當某塊內存還在被別的指針使用或者引用的時候,提前釋放某個指針指向的這塊內存。這種Premature Free會導致程序崩潰。

如果需要解決這種問題我們可以使用Development Mode的libgc,這 種使用方式需要修改代碼。libgc庫提供了三個函數用於處理Premature Free問題。

void gcFixPrematureFrees(void)

該函數會讓free函數失效,free函數不會釋放任何內存。內存的釋放會全交給libgc,libgc會自動判斷,在這塊內存沒有別人使用或者引用 後,會自動釋放。

void gcStopFixingPrematureFrees(void)

該函數會中止修復Premature free,是 gcFixPrematureFrees 的反操作。

void gcInitialize(void)

在程序啓動時候,libgc庫文件會自動調用gcInitialize函數。該函數通常是作爲一個預 設接口,用來調用gcFixPrematureFrees 函數。

使用方法如下:

#include

void gcInitialize(void)
{
gcFixPrematureFrees();
}

這三個函數的定義都在gct.h文件 中。

總結
以上介紹的是在Solaris下多種解決內存泄漏方法,每種方法都有自 己的優缺點,適用於不同的場合。我們把這幾種方法作了一個比較,供大家參考:

 

 

參考資料

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/laoeyu/archive/2006/06/08/781116.aspx

 

參考資料
1. Identifying Memory Management Bugs Within Applications Using the libumem Library
2. Using DTrace to Profile and Debug A C++ Program
3. 使用dbx調試程序
4. Using the C/C++ Garbage Collection Library, libgc
5. Solaris Dynamic Tracing Guide
6. Sanjeev Bagewadi's Weblog

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/laoeyu/archive/2006/06/08/781116.aspx

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