1. 程式人生 > >linux下檢測和定位記憶體洩漏位置的方法

linux下檢測和定位記憶體洩漏位置的方法

gtest:http://code.google.com/p/googletest/,可以下載最新的程式碼。下載後,可以參考gtest-1.6.0\make\Makefile寫自己的Makefile。

程式記憶體的資訊(/proc/self/smaps):

VMSIZE:      15316 KB
RSS:          2560 KB total
              1152 KB shared
               428 KB private clean
               980 KB private dirty

RSS(private dirty)最接近程式所使用的記憶體,特別是從heap分配的記憶體。

使用單元測試可以檢測記憶體洩漏。思路如下:

  1. 寫一個獲取當前記憶體的函式(獲取Private Dirty)。
  2. 函式開始執行時,記錄當前記憶體。
  3. 迴圈5萬/50萬/500萬次,執行某個目標函式(可能有洩漏的函式)。
  4. 每次迴圈都檢查記憶體,當記憶體增長了1M時,可以認定有記憶體洩漏。

當然目標函式是申請了記憶體,然後釋放記憶體,在生命週期結束時應該要釋放它的記憶體。

從頂級函式開始,或者從任意可能洩漏的函式開始,一直定位到記憶體洩漏的位置。可以使用utest中的mock來加快記憶體洩漏的速度。


在gtest-1.6.0同目錄下,寫Makefile如下:

# A sample Makefile for building Google Test and using it in user
# tests.  Please tweak it to suit your environment and project.  You
# may want to move it to your project's root directory.
#
# SYNOPSIS:
#
#   make [all]  - makes everything.
#   make TARGET - makes the given target.
#   make clean  - removes all files generated by make.

# Please tweak the following variable definitions as needed by your
# project, except GTEST_HEADERS, which you can use in your own targets
# but shouldn't modify.

# Points to the root of Google Test, relative to where this file is.
# Remember to tweak this if you move this file.
GTEST_DIR = gtest-1.6.0

# Where to find user code.
USER_DIR = .

# Flags passed to the preprocessor.
CPPFLAGS += -I$(GTEST_DIR)/include

# Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra -O0

# All tests produced by this Makefile.  Remember to add new tests you
# created to the list.
TESTS = winlin_mem_leak_utest

# All Google Test headers.  Usually you shouldn't change this
# definition.
GTEST_HEADERS = $(GTEST_DIR)/include/gtest/*.h \
                $(GTEST_DIR)/include/gtest/internal/*.h

# House-keeping build targets.

all : $(TESTS)

clean :
	rm -f $(TESTS) gtest.a gtest_main.a *.o

# Builds gtest.a and gtest_main.a.

# Usually you shouldn't tweak such internal variables, indicated by a
# trailing _.
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/src/*.h $(GTEST_HEADERS)

# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized.  This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
gtest-all.o : $(GTEST_SRCS_)
	$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
            $(GTEST_DIR)/src/gtest-all.cc

gtest_main.o : $(GTEST_SRCS_)
	$(CXX) $(CPPFLAGS) -I$(GTEST_DIR) $(CXXFLAGS) -c \
            $(GTEST_DIR)/src/gtest_main.cc

gtest.a : gtest-all.o
	$(AR) $(ARFLAGS) 
[email protected]
$^ gtest_main.a : gtest-all.o gtest_main.o $(AR) $(ARFLAGS) [email protected] $^ # Builds a sample test. A test should link with either gtest.a or # gtest_main.a, depending on whether it defines its own main() # function. winlin_mem_leak_utest.o : $(USER_DIR)/winlin_mem_leak_utest.cpp $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/winlin_mem_leak_utest.cpp winlin_mem_leak_utest : winlin_mem_leak_utest.o gtest_main.a $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o
[email protected]

同目錄下,寫winlin_mem_leak_utest.cpp,內容如下:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <assert.h>

#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <string>
#include <fstream>
using namespace std;

#include "gtest/gtest.h"
using namespace testing;

// less
#define AssertLess(a, b)\
    EXPECT_TRUE(a < b); \
    if(a >= b){ \
        cout << "(" << #a << ")" \
            << "(" << a << ")" \
            << " < " \
            << "(" << #b << ")" \
            << "(" << b << ")" \
            << " failed!" \
            << endl; \
    }
#define LoopAssertLess(exit, a, b)\
    exit = (a >= b) ? true : exit; \
    AssertLess(a, b);
// greater
#define AssertGreater(a, b)\
    EXPECT_TRUE(a > b); \
    if(a < b){ \
        cout << "(" << #a << ")" \
            << "(" << a << ")" \
            << " > " \
            << "(" << #b << ")" \
            << "(" << b << ")" \
            << " failed!" \
            << endl; \
    }
#define LoopAssertGreater(exit, a, b)\
    exit = (a < b) ? true : exit; \
    AssertGreater(a, b);

// the memory leak size, in KB.
// default is 1024(1MB), if the program leak 1MB, we think it's a leak!.
#define MemoryLeakSize 1024
// the biger this value, the more memory leak canbe detected(take more time also).
#define MemoryLeakDetectLoop 1000

// begin the memory leak test loop. 
//      usage: BeginLoopMemLeakTest()
// loop 1,000 times. (detect 1000byte leak to 1M).
#define BeginLoopMemLeakTest()\
    BeginLoopMemLeakTestCount(MemoryLeakDetectLoop)
//
// loop 10,000 times. (detect 100byte leak to 1M).
#define BeginLoopMemLeakTest2() \
            BeginLoopMemLeakTestCount(MemoryLeakDetectLoop*10)
//
// loop 50,000 times (detect 10byte leak to 1M).
#define BeginLoopMemLeakTest3()\
            BeginLoopMemLeakTestCount(MemoryLeakDetectLoop*50)
//
// loop 500,000 times (detect 1byte leak to 1M).
#define BeginLoopMemLeakTest4()\
            BeginLoopMemLeakTestCount(MemoryLeakDetectLoop*500)
//
// loop 5,000,000 times
#define BeginLoopMemLeakTest5()\
            BeginLoopMemLeakTestCount(MemoryLeakDetectLoop*5000)
#define BeginLoopMemLeakTestCount(loop_count)\
    MemView __a(0); \
    bool __exit = false; \
    int __alloc_once_size = 0;/*the normal alloc size.*/ \
    for(int __i = 0; __i < loop_count && !__exit; __i++){ \
        if(true){
// end the memory leak test loop.
//      usage: EndLoopMemLeakTest()
// first time, the heap memory will totally free when pool delete it.
// second time, the memory will not free.
// third time, use the previous free memory.
// so here, if the memory is constant, we think it's ok and no memory leak.
#define EndLoopMemLeakTest()\
        } \
        MemView __c(0);\
        if(__alloc_once_size == 0){ \
            __alloc_once_size = __c.private_dirty - __a.private_dirty; \
        } \
        LoopAssertLess(__exit, __c.private_dirty - __a.private_dirty, __alloc_once_size + MemoryLeakSize);\
        if(__exit){ \
            cout << "leak detected loop #" << __i << endl;/**/ \
        } \
    }

#include "memview.cpp"

TEST(SimpleTest, MemoryLeakDetect){
    BeginLoopMemLeakTest3()
    
    new char[1]; // memory leak here
    
    EndLoopMemLeakTest()
}

沒有洩漏的結果:


執行3萬次可以檢測到1個位元組的洩漏。結果如下:


可運用在實際專案中。

相關推薦

linux檢測定位記憶體洩漏位置方法

gtest:http://code.google.com/p/googletest/,可以下載最新的程式碼。下載後,可以參考gtest-1.6.0\make\Makefile寫自己的Makefile。 程式記憶體的資訊(/proc/self/smaps): VMSIZE:

C++檢測定位記憶體洩漏的技巧

在實際開發過程中專案中由於各方面原因,總是有人抱怨存在記憶體洩漏,系統長時間執行之後,可用記憶體越來越少,萇至導致了某些服務失敗。記憶體洩漏是最難發現的常見錯誤之一,因為除非用完記憶體或呼叫malloc失敗,否則都不會導致任何問題。實際上,使用C/C++這類沒有垃圾回收機制

linux檢視cpu、記憶體硬碟大小

轉載至:http://blog.sina.com.cn/s/blog_535aa0930100ltz8.html 查cpu #dmesg |grep -i xeon CPU0: Intel(R) Xeon(R) CPU           E5520  @ 2.27G

如何在vslinux檢測記憶體洩露

1、記憶體洩漏簡介2、Windows平臺下的記憶體洩漏檢測 2.1、檢測是否存在記憶體洩漏問題2.2、定位具體的記憶體洩漏地方 3、Linux平臺下的記憶體洩漏檢測 4、總結 其實Windows、Linux下面的記憶體檢測都可以單獨開篇詳細介紹,方法和工

如何快速定位Android記憶體洩漏位置

如果所有的物件都可以被順利回收就沒有本文的誕生了,舉個簡單的例子,我們在開發中經常使用單例模式,單例的靜態特性導致其生命週期同應用一樣長。有時建立單例時如果我們需要Context物件,如果傳入的是Application的Context那麼不會有問題。如果傳入的是Activity的Context物件,那麼當

Linux定位記憶體洩漏

1. 什麼是記憶體洩漏 記憶體洩漏是指堆記憶體的洩漏。堆記憶體是指程式從堆中分配的、大小任意的(記憶體塊的大小可以在程式執行期決定)、使用完後必須顯示釋放的記憶體。應用程式一般使用malloc、realloc、new等函式從堆中分配到一塊記憶體,使用完後,程式

Linux檢視CPU、記憶體硬碟型號及相關資訊命令

smartctl version 5.33 [i386-redhat-linux-gnu] Copyright (C) 2002-4 Bruce Allen Home page is http://smartmontools.sourceforge.net/ === START OF INFORMATION

linux bash_profilebashrc區別

bash_profile和bashrc區別【.bash_profile 與 .bashrc 的區別】.bash_profile is executed for login shells, while .bashrc is executed for interactive non-login shells.【l

解決Linux serverclient 通過TCP通訊:accept成功接收卻報錯的問題

ipv4 socket error 實例代碼 ... lis col argc 例子   今天在寫簡單的TCP通訊例子的時候,遇到了一個問題:server 和client能夠連接成功,並且client也能夠正常發送,但server就是接收不到,在網上搜索一番後,終於解決了問

如何在linux檢測內存泄漏

nap 主程序 決定 行處理 sign cell 子進程 根據 參數重載 簡述 本文針對 linux 下的 C++ 程序的內存泄漏的檢測方法及其實現進行探討。其中包括 C++ 中的 new 和 delete 的基本原理,內存檢測子系統的實現原理和具體方法,以及內存泄漏檢測的

Linux安裝卸載軟件

20180324一、安裝方法:rpm工具、yum工具、源碼包 1、rpm工具:由redhat公司開發; yum工具:是由Python開發的; 源碼包:由C語言開發,C語言是Linux上最標準的程序語言。 二、rpm工具的使用1、在虛擬機上掛載一CD到/mnt/目錄下: mount /dev/cdrom /m

Unix / Linux nohup & 的區別

http app 後來 gts -s 周期 能夠 不同 history 聲明:本文首發 簡單教程,網址為 https://www.twle.cn/t/332#reply0 就在剛剛回家的路上,被前同事奪命三連 call 呼喚解決一個問題:為啥放在 crontab 裏的命

Visual Studio中檢測記憶體洩漏方法

Visual Studio中檢測記憶體洩漏的方法 #include <iostream> //可以定位到發生記憶體洩露 所在的檔案和具體那一行,用於檢測 malloc 分配的記憶體 #define _CRTDBG_MAP_ALLOC #include <s

linux檢視cpu,記憶體,硬碟等硬體資訊的方法

說明:Linux下可以在/proc/cpuinfo中看到每個cpu的詳細資訊。但是對於雙核的cpu,在cpuinfo中會看到兩個cpu。常常會讓人誤以為是兩個單核的cpu。原文地址: http://www.hpboys.com/659.html一、linux CPU大小    [

Linuxat crontab的基本運用以及臨時檔案基本管理

一、at的基本運用 在終端輸入watch -n 1 ls -R /mnt/           //監控檔案每秒檢視一次並以第歸的方式列出來 使用at命令制定延時任務 

LinuxTclexpect 的安裝

背景介紹:          因搭建遊戲中心的測試環境,需要安裝兩個程式tcl8.4.13-src.tar.gz、expect-5.43.0.tar.gz    安裝方法:    &n

Linuxprofilebashrc區別

Linux下profile和bashrc區別 1./etc/profile 用來設定系統環境引數,比如$PATH. 這裡面的環境變數是對系統內所有使用者生效的。 2./etc/bashrc 這個檔案設定系統bash shell相關的東西,對系統內所有使用者生效。只要

linux檢視系統屬性 Linux檢視新增環境變數

Linux下檢視和新增環境變數 #檢視tomcat安裝路徑 sudo find / -name *tomcat* $PATH:決定了shell將到哪些目錄中尋找命令或程式,PATH的值是一系列目錄,當您執行一個程式時,Linux在這些目錄下進行搜尋編譯連結。   編輯你的 PATH 宣告

linuxpollepoll核心原始碼剖析

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

根據記憶體洩漏位置新增斷點

_CrtSetBreakAlloc(XXX); XXX代表記憶體提示資訊中大括號中的數字。 Detected memory leaks! Dumping objects -> {98500} normal block at 0x05785AD0, 152 bytes long. Data: