valgrind檢查C/C++內存泄漏

valgrind --tool=memcheck --leak-check=full ./httptestios

 valgrind --tool=memcheck --leak-check=full --track-origins=yes --show-reachable=yes ./httptestc++

Valgrind 使用

用法: valgrind [options] prog-and-args [options]: 經常使用選項,適用於全部Valgrind工具編程

  1. -tool=<name> 最經常使用的選項。運行  valgrind中名爲toolname的工具。默認memcheck。
  2. h –help 顯示幫助信息。
  3. -version 顯示 valgrind內核的版本,每一個工具都有各自的版本。
  4. q –quiet 安靜地運行,只打印錯誤信息。
  5. v –verbose 更詳細的信息, 增長錯誤數統計。
  6. -trace-children=no|yes 跟蹤子線程? [no]
  7. -track-fds=no|yes 跟蹤打開的文件描述?[no]
  8. -time-stamp=no|yes 增長時間戳到LOG信息? [no]
  9. -log-fd=<number> 輸出LOG到描述符文件 [2=stderr]
  10. -log-file=<file> 將輸出的信息寫入到filename.PID的文件裏,PID是運行程序的進行ID
  11. -log-file-exactly=<file> 輸出LOG信息到 file
  12. -log-file-qualifier=<VAR> 取得環境變量的值來作爲輸出信息的文件名。 [none]
  13. -log-socket=ipaddr:port 輸出LOG到socket ,ipaddr:port

LOG信息輸出數組

  1. -xml=yes 將信息以xml格式輸出,只有memcheck可用
  2. -num-callers=<number> show <number> callers in stack traces [12]
  3. -error-limit=no|yes 若是太多錯誤,則中止顯示新錯誤? [yes]
  4. -error-exitcode=<number> 若是發現錯誤則返回錯誤代碼 [0=disable]
  5. -db-attach=no|yes 當出現錯誤, valgrind會自動啓動調試器gdb。[no]
  6. -db-command=<command> 啓動調試器的命令行選項[gdb -nw %f %p]

適用於Memcheck工具的相關選項:安全

  1. -leak-check=no|summary|full 要求對leak給出詳細信息? [summary]
  2. -leak-resolution=low|med|high how much bt merging in leak check [low]
  3. -show-reachable=no|yes show reachable blocks in leak check? [no]

 

// Automatic objects are not destroyed as a result of calling exit()

#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <vector>
#include <algorithm>
#include <sstream>
#include <string>
int fail(const std::string str)
{
    std::cerr<< str << std::endl;
    exit(1);
}

const std::string usage()
{
    std::string a = "a";
    return a;
}

int main()
{
    fail(usage());
    return 0;
}
View Code

$ g++ -std=c++0x main.cpp -o xmain多線程

$ valgrind ./xmainsocket

==18699== definitely lost: 0 bytes in 0 blocks
==18699== indirectly lost: 0 bytes in 0 blocks
==18699== possibly lost: 26 bytes in 1 blocks
==18699== still reachable: 0 bytes in 0 blocks
==18699== suppressed: 0 bytes in 0 blocks
==18699== Rerun with --leak-check=full to see details of leaked memoryide

 

coredump文件

什麼是coredump函數

一般狀況下coredmp包含了程序運行時的內存,寄存器狀態,堆棧指針,內存管理信息等。能夠理解爲把程序工做的當前狀態存儲成一個文件。許多程序和操做系統出錯時會自動生成一個core文件。工具

成程序coredump的緣由不少,這裏根據以往的經驗總結一下:

1 內存訪問越界
  a) 因爲使用錯誤的下標,致使數組訪問越界
  b) 搜索字符串時,依靠字符串結束符來判斷字符串是否結束,可是字符串沒有正常的使用結束符
  c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操做函數,將目標字符串讀/寫爆。應該使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函數防止讀寫越界。
 
2 多線程程序使用了線程不安全的函數。
應該使用下面這些可重入的函數,尤爲注意紅色標示出來的函數,它們很容易被用錯:
asctime_r(3c) gethostbyname_r(3n) getservbyname_r(3n) ctermid_r(3s) gethostent_r(3n) getservbyport_r(3n) ctime_r(3c) getlogin_r(3c) getservent_r(3n) fgetgrent_r(3c) getnetbyaddr_r(3n) getspent_r(3c) fgetpwent_r(3c) getnetbyname_r(3n) getspnam_r(3c) fgetspent_r(3c) getnetent_r(3n) gmtime_r(3c) gamma_r(3m) getnetgrent_r(3n) lgamma_r(3m) getauclassent_r(3) getprotobyname_r(3n) localtime_r(3c) getauclassnam_r(3) etprotobynumber_r(3n) nis_sperror_r(3n) getauevent_r(3) getprotoent_r(3n) rand_r(3c) getauevnam_r(3) getpwent_r(3c) readdir_r(3c) getauevnum_r(3) getpwnam_r(3c)strtok_r(3c) getgrent_r(3c) getpwuid_r(3c) tmpnam_r(3s) getgrgid_r(3c) getrpcbyname_r(3n) ttyname_r(3c) getgrnam_r(3c) getrpcbynumber_r(3n) gethostbyaddr_r(3n) getrpcent_r(3n)
 
3 多線程讀寫的數據未加鎖保護。
對於會被多個線程同時訪問的全局數據,應該注意加鎖保護,不然很容易形成core dump
 
4 非法指針
  a) 使用空指針
  b) 隨意使用指針轉換。一個指向一段內存的指針,除非肯定這段內存原先就分配爲某種結構或類型,或者這種結構或類型的數組,不然不要將它轉換爲這種結構或類型 的指針,而應該將這段內存拷貝到一個這種結構或類型中,再訪問這個結構或類型。這是由於若是這段內存的開始地址不是按照這種結構或類型對齊的,那麼訪問它 時就很容易由於bus error而core dump. 總線錯誤(bus   error)一般是指針強制轉換,致使CPU讀取數據違反了必定的總線規則。《c專家編程》
 

#include <stdlib.h>

#include <stdio.h>

#if defined(__GNUC__)

# if defined(__i386__)

        /* Enable Alignment Checking on x86 */

        __asm__("pushf\norl $0x40000,(%esp)\npopf");

# elif defined(__x86_64__)

        /* Enable Alignment Checking on x86_64 */

        __asm__("pushf\norl $0x40000,(%rsp)\npopf");

# endif

#endif

 

int main() {

 

 

 

        union{

                char a[10];

                int i;

        }u;

 

        int *p =(int*)&(u.a[1]);

        *p =17;

        printf("%d\n", *p);

}

 

緣由是:

x86體系結構會把地址對齊以後,訪問兩次,而後把第一次的尾巴和第二次的頭拼起來。

若是不是x86,那種體系結構下的機器不願自動幹這活,就會產生core。

若是在代碼中將對齊檢查功能打開,運行後能顯示bus error。


5 堆棧溢出
不要使用大的局部變量(由於局部變量都分配在棧上),這樣容易形成堆棧溢出,破壞系統的棧和堆結構,致使出現莫名其妙的錯誤。

內存泄漏memory leak

在一般的編程開發與應用中,寬泛地講,內存泄漏是分配了內存可是沒有在程序終止前釋放。嚴格且更有實際意義地講,內存泄漏是分配了某塊內存可是隨後程序再也不擁有指向該內存的任何指針了。內存泄露檢測工具valgrind使用的即是嚴格意義上內存泄露檢測原則。下文若是沒有特殊說明,一律指嚴格定義的內存泄露。內存泄露潛在地引發顯著的堆消耗,特別對於長久持續運行的程序。關於「still reachable」類型的Valgrind內存泄露檢測報告僅適用於寬泛定義的內存泄露。假如使用valgrind工具檢測到了程序出現「still reachable」,說明程序沒有釋放這種類型的內存塊,可是並不表明這些內存塊永遠的丟失了,不能被釋放了,由於程序依然擁有指向這些內存塊的指針。通常而言,它們不會引發嚴格意義上的內存泄露形成的問題(潛在的堆空間消耗以至無內存可用),因此不用擔憂這些「still reachable」內存塊。這是由於這些內存塊一般申請一次,在進程的整個生命週期內一直保持着引用。固然,你也能夠全程確保你的程序釋放掉全部分配的內存。由於OS會在進程終止後回收進程的全部內存,所以這樣作的意義不大。相反,若是存在真正的內存泄露,也許僅僅引發進程消耗的內存多於所需,也許程序運行時間足夠長,引發一個進程耗盡內存。

相關文章
相關標籤/搜索