linux C記憶體洩露檢測實現及記憶體洩露檢測的一般方法
linux中,由於使用malloc或alloc而沒有free掉申請的記憶體,就會造成記憶體的洩露。通常,來講為了避免記憶體洩露的情況出現,一般要求,我們儘量的malloc之後,呼叫free。但是總會有忘記free的時候啊。一般可以有如下幾種方式來避免記憶體洩露:
1) 使用智慧指標,這個在C++中較為常見;
2) 使用記憶體池;
3) 自己封裝一層malloc/free等等。當申請記憶體時,將申請資訊放入到一個已分配記憶體資訊連結串列裡面。free時,刪除對應的資訊表的節點。在程式執行結束前,掃瞄該資訊表,若還存在資訊節點,那麼該節點記錄的就是洩露的記憶體資訊。若連結串列為空,那就是說沒有發生記憶體洩露;
4)使用檢測工具檢測記憶體洩露,進而修補程式,這樣的工具有比如Valgrind等等。
以下,給出一個按方式3實現的記憶體洩露檢測的實現版本,程式碼量本身不多。
leak_detector_c.h檔案
#ifndef LEAK_DETECTOR_C_H #define LEAK_DETECTOR_C_H #define FILE_NAME_LENGTH 256 #define OUTPUT_FILE "/home/leak_info.txt" /*this file should be created first!*/ #define malloc(size) xmalloc (size, __FILE__, __LINE__) #define calloc(elements, size) xcalloc (elements, size, __FILE__, __LINE__) #define free(mem_ref) xfree(mem_ref) struct _MEM_INFO { void *address; unsigned int size; char file_name[FILE_NAME_LENGTH]; unsigned int line; }; typedef struct _MEM_INFO MEM_INFO; struct _MEM_LEAK { MEM_INFO mem_info; struct _MEM_LEAK * next; }; typedef struct _MEM_LEAK MEM_LEAK; void add(MEM_INFO alloc_info); void erase(unsigned pos); void clear(void); void * xmalloc(unsigned int size, const char * file, unsigned int line); void * xcalloc(unsigned int elements, unsigned int size, const char * file, unsigned int line); void xfree(void * mem_ref); void add_mem_info (void * mem_ref, unsigned int size, const char * file, unsigned int line); void remove_mem_info (void * mem_ref); void report_mem_leak(void); #endif
leak_detector_c.c檔案
#include <stdio.h> #include <malloc.h> #include <string.h> #include "leak_detector_c.h" #undef malloc #undef calloc #undef free static MEM_LEAK * ptr_start = NULL; static MEM_LEAK * ptr_next = NULL; /* * adds allocated memory info. into the list * */ void add(MEM_INFO alloc_info) { MEM_LEAK * mem_leak_info = NULL; mem_leak_info = (MEM_LEAK *) malloc (sizeof(MEM_LEAK)); mem_leak_info->mem_info.address = alloc_info.address; mem_leak_info->mem_info.size = alloc_info.size; strcpy(mem_leak_info->mem_info.file_name, alloc_info.file_name); mem_leak_info->mem_info.line = alloc_info.line; mem_leak_info->next = NULL; if (ptr_start == NULL) { ptr_start = mem_leak_info; ptr_next = ptr_start; } else { ptr_next->next = mem_leak_info; ptr_next = ptr_next->next; } } /* * erases memory info. from the list * */ void erase(unsigned pos) { unsigned index = 0; MEM_LEAK * alloc_info, * temp; if(pos == 0) { MEM_LEAK * temp = ptr_start; ptr_start = ptr_start->next; free(temp); } else { for(index = 0, alloc_info = ptr_start; index < pos; alloc_info = alloc_info->next, ++index) { if(pos == index + 1) { temp = alloc_info->next; alloc_info->next = temp->next;
if(temp->next==NULL)
{
ptr_next = alloc_info;
}
free(temp);
break;
}
}
}
}
/*
* deletes all the elements from the list
*/
void clear()
{
MEM_LEAK * temp = ptr_start;
MEM_LEAK * alloc_info = ptr_start;
while(alloc_info != NULL)
{
alloc_info = alloc_info->next;
free(temp);
temp = alloc_info;
}
ptr_start=NULL;
}
/*
* replacement of malloc
*/
void * xmalloc (unsigned int size, const char * file, unsigned int line)
{
void * ptr = malloc (size);
if (ptr != NULL)
{
add_mem_info(ptr, size, file, line);
}
return ptr;
}
/*
* replacement of calloc
*/
void * xcalloc (unsigned int elements, unsigned int size, const char * file, unsigned int line)
{
unsigned total_size;
void * ptr = calloc(elements , size);
if(ptr != NULL)
{
total_size = elements * size;
add_mem_info (ptr, total_size, file, line);
}
return ptr;
}
/*
* replacement of free
*/
void xfree(void * mem_ref)
{
remove_mem_info(mem_ref);
free(mem_ref);
}
/*
* gets the allocated memory info and adds it to a list
*
*/
void add_mem_info (void * mem_ref, unsigned int size, const char * file, unsigned int line)
{
MEM_INFO mem_alloc_info;
/* fill up the structure with all info */
memset( &mem_alloc_info, 0, sizeof ( mem_alloc_info ) );
mem_alloc_info.address = mem_ref;
mem_alloc_info.size = size;
strncpy(mem_alloc_info.file_name, file, FILE_NAME_LENGTH);
mem_alloc_info.line = line;
/* add the above info to a list */
add(mem_alloc_info);
}
/*
* if the allocated memory info is part of the list, removes it
*
*/
void remove_mem_info (void * mem_ref)
{
unsigned short index;
MEM_LEAK * leak_info = ptr_start;
/* check if allocate memory is in our list */
for(index = 0; leak_info != NULL; ++index, leak_info = leak_info->next)
{
if ( leak_info->mem_info.address == mem_ref )
{
erase ( index );
break;
}
}
}
/*
* writes all info of the unallocated memory into a file
*/
void report_mem_leak(void)
{
unsigned short index;
MEM_LEAK * leak_info;
FILE * fp_write = fopen (OUTPUT_FILE, "w+");
char info[1024];
if(fp_write != NULL)
{
sprintf(info, "%s\r\n", "Memory Leak Summary");
fwrite(info, (strlen(info)) , 1, fp_write);
sprintf(info, "%s\r\n", "-----------------------------------");
fwrite(info, (strlen(info)) , 1, fp_write);
for(leak_info = ptr_start; leak_info != NULL; leak_info = leak_info->next)
{
sprintf(info, "address : %d\r\n", leak_info->mem_info.address);
fwrite(info, (strlen(info)) , 1, fp_write);
sprintf(info, "size : %d bytes\r\n", leak_info->mem_info.size);
fwrite(info, (strlen(info)) , 1, fp_write);
sprintf(info, "file : %s\r\n", leak_info->mem_info.file_name);
fwrite(info, (strlen(info)) , 1, fp_write);
sprintf(info, "line : %d\r\n", leak_info->mem_info.line);
fwrite(info, (strlen(info)) , 1, fp_write);
sprintf(info, "%s\r\n", "-----------------------------------");
fwrite(info, (strlen(info)) , 1, fp_write);
printf("addr=%d,size=%d,file=%s,line=%d\n"
,leak_info->mem_info.address
,leak_info->mem_info.size
,leak_info->mem_info.file_name
,leak_info->mem_info.line);
}
fclose(fp_write);
}
else
{
}
/*clear();*/
}
使用時,只需將以上兩個檔案放入到你的工程目錄下,並在主函式裡面呼叫report_mem_leak就OK了。
測試test.c檔案
#include "leak_detector_c.h"
int main()
{
char * ptr1 = (char *)malloc(10);
int * ptr2 = (int *)calloc(10, sizeof(int));
float * ptr3 = (float *) calloc(15, sizeof(float));
free(ptr2);
atexit(report_mem_leak);
return 0;
}
編譯test.c並執行,可以在/home/leak_info.txt檔案中,看到兩條記憶體洩露記錄。
總的來說,這樣的檢測方式還是有一定效果的,但是同時記憶體資訊連結串列節點也使用了malloc來申請記憶體,這就造成了一定的額外的記憶體開銷。
我覺得要避免記憶體洩露,首先是自身要養成良好的程式設計習慣,然後是使用相關的方法和工具對程式碼進行檢測,最後是要閱讀程式碼了。工具也並不能檢測出所有的記憶體洩露,在這個時候只能靠自己去閱讀程式碼分析程式碼了,人畢竟比機器靈活嘛!
./autogen.sh
./configure --host=powerpc-linux CC=powerpc-linux-gnu-gcc CPP=powerpc-linux-gnu-cpp CXX=powerpc-linux-gnu-g++ --prefix=/mnt/nand
make
make install
./valgrind --tool=memcheck --vgdb=no ./memleak
注意:
1. --prefix=/mnt/nand 指定的目錄要與開發板上放置的目錄一致
2. 引數必須 --vgdb=no 否則會如下錯誤(可能因為我嵌入式linux 沒有整合gdb)
[email protected]:/mnt/nand/bin# ./valgrind --tool=memcheck ./memleak
==1300== Memcheck, a memory error detector
==1300== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==1300== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==1300== Command: ./memleak
==1300==
==1300== error 2 No such file or directory
==1300== mknod /tmp/vgdb-pipe-from-vgdb-to-1300-by-root-on-/bin/hostname
==1300== valgrind: fatal error: vgdb FIFOs cannot be created.
相關推薦
linux C記憶體洩露檢測實現及記憶體洩露檢測的一般方法
linux中,由於使用malloc或alloc而沒有free掉申請的記憶體,就會造成記憶體的洩露。通常,來講為了避免記憶體洩露的情況出現,一般要求,我們儘量的malloc之後,呼叫free。但是總會有忘記free的時候啊。一般可以有如下幾種方式來避免記憶體洩露: 1)
c語言堆與棧及記憶體分配
原文:http://www.cnblogs.com/TonyEwsn/archive/2010/01/29/1659496.html 格式和部分內容稍作修改。 在計算機領域,堆疊是一個不容忽視的概念,我們編寫的C語言程式基本上都要用到。但對於很多的初學著來說,堆疊是
Linux c++,用訊號量實現消費者生產者佇列(程式碼可直接通過編譯)
//用訊號量實現的一個消費者生產者佇列, #include <iostream> #include <pthread.h> #include <semaphore.h> #include <errno.h> #include <queue>
Linux C Socket UDP程式設計介紹及例項
1、UDP網路程式設計主要流程 UDP協議的程式設計框架,客戶端和伺服器之間的差別在於伺服器必須使用bind()函式來繫結偵聽的本地UDP埠,而客戶端則可以不進行繫結,直接傳送到伺服器地址的某個埠地址。框圖如圖1.3所示 UDP協議的伺服器端流程 伺服器流程主要分為下述6個
nginx原始碼分析—記憶體池結構ngx_pool_t及記憶體管理
本部落格(http://blog.csdn.net/livelylittlefish)貼出作者(阿波)相關研究、學習內容所做的筆記,歡迎廣大朋友指正!Content0. 序1. 記憶體池結構1.1 ngx_pool_t結構1.2 其他相關結構1.3 ngx_pool_t的邏輯
C++多型的實現及原理詳細解析
C++的多型性用一句話概括就是: 在基類的函式前加上virtual關鍵字,在派生類中重寫該函式,執行時將會根據物件的實際型別來呼叫相應的函式。 如果物件型別是派生類,就呼叫派生類的函式;如果物件型別是基類,就呼叫基類的函式,此為多型的表現; 在看看以下幾點: 1. 用vir
Linux c==使用父子程序實現TCP通訊
include include include include include include include include define MY_PORT 3333 int main(int argc ,char **argv) { int liste
獲取Linux命令幫助信息,及man手冊的使用方法
Linux man 幫助 Linux中命令的類型 Linux 中命令類型分為內部命令和外部命令。 使用type命令判斷內部和外部命令,示例如下: [root@centos7 ~]# type cd cd is a shell builtin #
linux伺服器中不支援soap及bcmul函式的結局方法
新的程式裡用了webserice介面,部到伺服器,先是提示:bcmul() 函式不可用,網上搜索一番,得知這是php的高精度函式,需要在編譯php的時候加入此模組,於是在編譯腳本里增添 “–enable-bcmath” 後重新編譯、重啟apache然後此錯誤解決; 然後有遇到報錯“Class ‘SoapCl
Linux C 程式執行 shell 命令並獲取返回結果的方法
據說有統計資料表明,程式碼的缺陷率是一定的,與所使用的語言無關。Linux提供了很多的實用工具和指令碼,在程式中呼叫工具和指令碼,無疑可以簡化程式,從而降低程式碼的缺陷數目。Linux shell 指令碼也是一個強大的工具,我們可以根據需要編制指
linux centos7 下Nginx伺服器實現URL重寫去掉index.php方法,跟Apache還是不一樣的。
想要的URL :http://localhost/Admin/ 而自己的是http://localhost/index.php/Admin/ 方法: 在nginx配置檔案nginx.conf中新增: location / { if ( !e $request_filename )
C#中呼叫SAPI實現語音識別的2種方法
通過微軟的SAPI,不僅僅可以實現語音合成TTS,同樣可以實現語音識別SR。下面我們就介紹並貼出相關程式碼。主要有兩種方式: 1、使用COM元件技術,不管是C++,C#,Delphi都能玩的轉,開發出來的東西在XP和WIN7都能跑。(注意要引入系統元件SpeechLib,XP要安裝識別引擎) 2、
Linux系統date命令的引數及獲取時間戳的方法
date指令相關用法示例 date 用法: date [OPTION]... [+FORMAT] date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] 直接輸入date date 指定格式顯示時間: date +%Y
linux mac svn ignore忽略檔案及資料夾最好用方法 之*妙用
一、忽略單個檔案 忽略檔案必須要進入到檔案的當前目錄,比如要忽略這個database.php配置檔案。 先進入application資料夾,輸入兩條命令語法如下: svn propset svn:ignore '要忽略的檔名' ./ svn ci -m 'ignore
Delphi 中自定義異常及異常處理的一般方法
delphi中異常定義如下: TCustomException = class(Exception) private public constructor Create(const Msg: string );
Linux C 程式設計記憶體洩露檢測工具(二):memwatch
Memwatch簡介 在三種檢測工具當中,設定最簡單的算是memwatch,和dmalloc一樣,它能檢測未釋放的記憶體、同一段記憶體被釋放多次、位址存取錯誤及不當使用未分配之記憶體區域。請往http://www.linkdata.se/sourcecode.html下載最
linux c 程式碼測試之記憶體越界及記憶體洩露
記憶體越界是我們軟體開發中經常遇到的一個問題。不經意間的複製常常導致很嚴重的後果。經常使用memset、memmove、strcpy、strncpy、strcat、sprintf的朋友肯定對此印象深刻,下面就是我個人在開發中實際遇到的一個開發問題,頗具典型。 #
C語言動態記憶體分配:(一)malloc/free的實現及malloc實際分配/釋放的記憶體
一、malloc/free概述 malloc是在C語言中用於在程式執行時在堆中進行動態記憶體分配的庫函式。free是進行記憶體釋放的庫函式。 1、函式原型 #include <stdlib.h> void *malloc( size_t size
使用ReferenceQueue實現對ClassLoader垃圾回收過程的觀察、以及由此引發的ClassLoader記憶體洩露的場景及排查過程
1 使用Reference/ReferenceQueue觀察Class和ClassLoader的解除安裝在java中,存在著強引用(=),軟引用(SoftReference),弱引用(WeakReference),虛引用(PhantomReference)這4種引用型別。如果
java中遠端監控Linux主機CPU及記憶體程式碼實現
對於遠端監控Linux主機系統CPU,記憶體使用情況,以前也使用了top等命令,但是最後還是覺得使用vmstat比較好. 執行top命令獲得系統CPU使用情況有兩個缺點, 第一執行top命令,執行的shell語句相對複雜. 用top命令獲得CPU使用情況的shell語句 t