利用Jemalloc進行內存泄漏的調試


內存不符預期的不斷上漲,可能的原因是內存泄漏,例如new出來的對象未進行delete就重新進行復制,使得之前分配的內存塊被懸空,應用程序沒辦法訪問到那部分內存,並且也沒有辦法釋放;在C++中,STL容器都會有clear()方法並且伴隨RAII原則對容器里元素進行清理,但除了STL還有可能是字符串不斷地在進行累加,不斷的分配出新的內存塊存放增長的字符串。

cppzh 群 內看到討論利用jemalloc對內存占用的調試,能夠清楚的 dump 出內存的使用情況,便嘗試了下。

安裝

# 用於生成 pdf
yum -y install graphviz ghostscript

wget https://github.com/jemalloc/jemalloc/archive/5.1.0.tar.gz
tar zxvf 5.1.0.tar.gz
cd jemalloc-5.1.0/
./autogen.sh
./configure --prefix=/usr/local/jemalloc-5.1.0 --enable-prof
make -j
make install

程序退出時的用例和檢查

# run
MALLOC_CONF=prof_leak:true,lg_prof_sample:0,prof_final:true LD_PRELOAD=/usr/local/jemalloc-5.1.0/lib/libjemalloc.so.2  ./a.out

# 查看內存占用情況
/usr/local/jemalloc-5.1.0/bin/jeprof a.out jeprof.34447.0.f.heap
> top

長時間運行-測試用例

對於長時間運行的程序,例如服務端程序通常不能夠退出,jemalloc提供每增長指定大小進行一次內存dump。

下面這個例子mock長時間運行的程序,分別測試順序容器(vector)和關聯容器(map),string 和最基本的new,並且每100ms執行1000次,代表服務端的運行情況。

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <chrono>
#include <thread>

int main() {

    std::vector<int> vec;
    std::map<int, int> mp;
    std::string s;
    for (;;) {
        for (int i = 0; i < 1000; ++i) {
            vec.push_back(i);
            mp[rand()] = i;
            s += "xxxx";
            new char[4];
        }
        std::this_thread::sleep_for(std::chrono::microseconds(100));
    }

    return 0;
}

編譯運行:

g++ test.cc -o a.out

將環境變量MALLOC_CONF設置為prof:true,lg_prof_interval:26使jemalloc開啟prof並且每2^26字節(64M)大小進行一次dump,並且利用LD_PRELOAD 環境變量代替。

export MALLOC_CONF="prof:true,lg_prof_interval:26"
LD_PRELOAD=/usr/local/jemalloc-5.1.0/lib/libjemalloc.so.2  ./a.out

[root@pwh c++]# ls -l -t
total 212
-rw-r--r-- 1 root root  5208 Dec 19 14:31 jeprof.17988.17.i17.heap
-rw-r--r-- 1 root root  5206 Dec 19 14:31 jeprof.17988.16.i16.heap
-rw-r--r-- 1 root root  5204 Dec 19 14:31 jeprof.17988.15.i15.heap
-rw-r--r-- 1 root root  5204 Dec 19 14:31 jeprof.17988.14.i14.heap
-rw-r--r-- 1 root root  5204 Dec 19 14:31 jeprof.17988.13.i13.heap
-rw-r--r-- 1 root root  5204 Dec 19 14:31 jeprof.17988.12.i12.heap
-rw-r--r-- 1 root root  5204 Dec 19 14:31 jeprof.17988.11.i11.heap
-rw-r--r-- 1 root root  5200 Dec 19 14:31 jeprof.17988.10.i10.heap
-rw-r--r-- 1 root root  5200 Dec 19 14:31 jeprof.17988.9.i9.heap
-rw-r--r-- 1 root root  5200 Dec 19 14:31 jeprof.17988.8.i8.heap
-rw-r--r-- 1 root root  5198 Dec 19 14:31 jeprof.17988.7.i7.heap
-rw-r--r-- 1 root root  5198 Dec 19 14:31 jeprof.17988.6.i6.heap
...

結果分析

由於是每隔一段內存大小進行的dump,每個文件都是內存的片段信息,利用--base指定從哪一份heap文件開始分析。

$ /usr/local/jemalloc-5.1.0/bin/jeprof a.out --base=jeprof.17988.0.i0.heap  jeprof.17988.17.i17.heap
$ /usr/local/jemalloc-5.1.0/bin/jeprof a.out --base=jeprof.17988.0.i0.heap  jeprof.17988.17.i17.heap
Using local file a.out.
Argument "MSWin32" isn't numeric in numeric eq (==) at /usr/local/jemalloc-5.1.0/bin/jeprof line 5123.
Argument "linux" isn't numeric in numeric eq (==) at /usr/local/jemalloc-5.1.0/bin/jeprof line 5123.
Using local file jeprof.17988.17.i17.heap.
Welcome to jeprof!  For help, type 'help'.
(jeprof) top
Total: 1002.5 MB
   754.5  75.3%  75.3%    754.5  75.3% __gnu_cxx::new_allocator::allocate@4031fc
   124.0  12.4%  87.6%    124.0  12.4% __gnu_cxx::new_allocator::allocate@402fac
   124.0  12.4% 100.0%    124.0  12.4% std::__cxx11::basic_string::_M_mutate
     0.0   0.0% 100.0%   1002.5 100.0% __libc_start_main
     0.0   0.0% 100.0%   1002.5 100.0% _start
     0.0   0.0% 100.0%   1002.5 100.0% main
     0.0   0.0% 100.0%    754.5  75.3% std::_Rb_tree::_M_create_node
     0.0   0.0% 100.0%    754.5  75.3% std::_Rb_tree::_M_emplace_hint_unique
     0.0   0.0% 100.0%    754.5  75.3% std::_Rb_tree::_M_get_node
     0.0   0.0% 100.0%    124.0  12.4% std::_Vector_base::_M_allocate

# 導出為 pdf
/usr/local/jemalloc-5.1.0/bin/jeprof --pdf a.out  --base=jeprof.17988.0.i0.heap jeprof.17988.17.i17.heap   > a.pdf

統計內存使用情況

jemalloc

取了新的一段內存區間將其導出為pdf后,總共分配使用718MB內存,其中在map的[]的操作符重載函數中占用了514.5MB,為string分配了60MB,為vector分配了60MB,而最基礎的new char[4]的調用棧是停留在main()中,所以main()也占用了84MB,得到的數據和Total MB(718.5MB)吻合。

ref


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM