linux下valgrind內存問題排查

  c/c++的內存管理一直都是程序猿最頭痛的事情,內存越界、數組越界、內存泄漏、內存溢出、野指針、空指針..., 隨便一個問題均可能讓程序崩潰。並且每每問題的源頭都比較隱蔽,讓人很難排查出問題的根源所在。
  想要解決這個問題,還得從問題的根源入手。valgrind是一個強大的內存管理工具,經常使用來檢測內存泄漏和內存的非法使用,用好了能夠很好的從根源上解決c/c++內存管理的問題。linux

1.valgrind的主要功能

  virgrind能夠用來檢測程序開發中的絕大多數內存,函數、緩存使用、多線程競爭訪問內存、堆棧問題,是一個linux下功能很是強大內存檢測工具。c++

1 valgrind工具

  valgrind-tool=<name> 最經常使用的選項。運行valgrind中名爲toolname的工具。默認memcheck。數組

  memcheck:這是valgrind應用最普遍的工具,一個重量級的內存檢查器,可以發現開發中絕大多數內存錯誤問題,好比:使用未初始化的內存,使用已經釋放了的內存,內存訪問越界等。下面將重點介紹此功能。緩存

  callgrind: 主要用來檢查程序中函數調用過程當中出現的問題。多線程

  cachegrind: 主要用來檢查程序中緩存使用出現的問題。socket

  helgrind: 主要用來檢查多線程程序中出現的競爭問題。ide

  massif: 主要用來檢查程序中堆棧使用中出現的問題。函數

  extension: 能夠利用core提供的功能,本身編寫特定的內存調試工具。工具

2 valgrind memcheck

2.1memcheck內存檢測原理

  valid-value表:
  對於進程的整個地址空間中的每個字節(byte),都有與之對應的8個bits,對於CPU的每一個寄存器,也有一個與之對應的bit向量。這些bits負責記錄該字節或者寄存器值是否具備有效的、已經初始化的值。
  valid-Address表:
  對於進程整個地址空間中的一個字節(byte),還有與之對應的1bit,負責記錄該地址是否可以被讀寫。
  內存檢測原理:
  當要讀寫內存中的某個字節時,首先檢查這個字節對應的address bit。若是該address bit顯示該位置是無效位置,memcheck則報告內存讀寫錯誤。valgrind內核至關於一個虛擬的CPU環境,當內存中的某個字節被加載到真實的CPU中時,該字節對應的value bit也被加載到虛擬的CPU環境中,一旦寄存器中的值,被用來產生內存地址,或者該值可以影響程序的輸出,則mencheck會檢查對應的value bits,若是該值還沒有初始化,則會報告使用未初始化內存錯誤。優化

2.2 memcheck內存檢測

2.2.1 準備源碼

  建立gdbmem.cpp源碼文件,準備待檢測的代碼以下:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <malloc.h>
#include<pthread.h>
#include<string.h>

//memory access overflow
char* stringcopy(char* psrc)
{
    int len = strlen(psrc) + 1;
    char* pdst = (char*)malloc(len);//12
    memset(pdst, 0, len * 2);//13
    memcpy(pdst, psrc, len*2);//14
    return pdst;
}

//array assess overflow
void printarray(int arry[], int arrysize)
{
    int i = 0;
    for(; i < arrysize; i++)
    //for(i = arrysize-1; i >= 0; i--)
    {
        printf("arry[%d]:%d\n",i, arry[i]);
    }
    printf("arry[%d]:%d\n",i+1, arry[i+1]);//27
}

//main body
int main(int narg, const char** args)
{
    char* pwildptr;
    char* pstr = "this is a memory debug program!\n";
    int array[10] = {1,2,3,4,5,6,7,8,9,10};
    char* ptmp = stringcopy(pstr);//36
    //memory leak
    char* ptmp2 = (char*)malloc(100);//38
    memset(ptmp2, 0, 100);
    // memory write overflow
    printf(ptmp);//41
    // array tip assess overflow
    printarray(array, 10);//43
    free(ptmp);//44
    printf("%p", pwildptr);//45
    //wild ptr copy
    memcpy(ptmp, ptmp2, 20);//47
    printf(ptmp);//48
    return 0;
}

2.2.2 編譯源碼:

$g++ -g -O0 -c gdbmem.cpp#-g:編譯帶調試信息的obj文件,-O0:不優化
$g++ -o gdbmem gdbmem.o
  編譯後將在當前目錄下生成gdbmem可執行文件。

2.2.3 valgrind內存檢測

  valgring 對gdbmem進行內存檢測

$ valgrind --tool=memcheck --leak-check=full --track-fds=yes ./gdbmem
==10668== Memcheck, a memory error detector
==10668== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10668== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==10668== Command: ./gdbmem
==10668== 
==10668== Invalid write of size 8
==10668==    at 0x4C3453F: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x40075D: stringcopy(char*) (gdbmem.cpp:13)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668==  Address 0x5204060 is 32 bytes inside a block of size 33 alloc'd
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid write of size 1
==10668==    at 0x4C34558: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x40075D: stringcopy(char*) (gdbmem.cpp:13)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668==  Address 0x5204080 is 16 bytes after a block of size 48 in arena "client"
==10668== 
==10668== Invalid write of size 8
==10668==    at 0x4C326CB: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400778: stringcopy(char*) (gdbmem.cpp:14)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668==  Address 0x5204060 is 32 bytes inside a block of size 33 alloc'd
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid write of size 2
==10668==    at 0x4C32723: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400778: stringcopy(char*) (gdbmem.cpp:14)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668==  Address 0x5204080 is 16 bytes after a block of size 48 in arena "client"
==10668== 
this is a memory debug program!
arry[0]:1
arry[1]:2
arry[2]:3
arry[3]:4
arry[4]:5
arry[5]:6
arry[6]:7
arry[7]:8
arry[8]:9
arry[9]:10
arry[11]:-623874025
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E8890E: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Use of uninitialised value of size 8
==10668==    at 0x4E84711: _itoa_word (_itoa.c:180)
==10668==    by 0x4E8812C: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E84718: _itoa_word (_itoa.c:180)
==10668==    by 0x4E8812C: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E881AF: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E87C59: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E87CE2: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)

  main函數45行,memcpy(ptmp, ptmp2, 20);讀取已經被釋放的內存,致使memcheck報錯。

==10668== Invalid write of size 8
==10668==    at 0x4C326CB: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008FE: main (gdbmem.cpp:47)
==10668==  Address 0x5204040 is 0 bytes inside a block of size 33 free'd
==10668==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008D0: main (gdbmem.cpp:44)
==10668==  Block was alloc'd at
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid write of size 2
==10668==    at 0x4C32723: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008FE: main (gdbmem.cpp:47)
==10668==  Address 0x5204050 is 16 bytes inside a block of size 33 free'd
==10668==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008D0: main (gdbmem.cpp:44)
==10668==  Block was alloc'd at
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid read of size 1
==10668==    at 0x4ED0760: strchrnul (strchr.S:24)
==10668==    by 0x4E87207: __find_specmb (printf-parse.h:108)
==10668==    by 0x4E87207: vfprintf (vfprintf.c:1312)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x40090F: main (gdbmem.cpp:48)
==10668==  Address 0x5204040 is 0 bytes inside a block of size 33 free'd
==10668==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008D0: main (gdbmem.cpp:44)
==10668==  Block was alloc'd at
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid read of size 1
==10668==    at 0x4E8741A: vfprintf (vfprintf.c:1324)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x40090F: main (gdbmem.cpp:48)
==10668==  Address 0x5204040 is 0 bytes inside a block of size 33 free'd
==10668==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008D0: main (gdbmem.cpp:44)
==10668==  Block was alloc'd at
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
0x40097d==10668== 
==10668== FILE DESCRIPTORS: 3 open at exit.
==10668== Open file descriptor 2: /dev/pts/4
==10668==    <inherited from parent>
==10668== 
==10668== Open file descriptor 1: /dev/pts/4
==10668==    <inherited from parent>
==10668== 
==10668== Open file descriptor 0: /dev/pts/4
==10668==    <inherited from parent>
==10668== 
==10668== 
==10668== HEAP SUMMARY:
==10668==     in use at exit: 100 bytes in 1 blocks
==10668==   total heap usage: 3 allocs, 2 frees, 1,157 bytes allocated
==10668== 
==10668== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400888: main (gdbmem.cpp:38)
==10668== 
==10668== LEAK SUMMARY:
==10668==    definitely lost: 100 bytes in 1 blocks
==10668==    indirectly lost: 0 bytes in 0 blocks
==10668==      possibly lost: 0 bytes in 0 blocks
==10668==    still reachable: 0 bytes in 0 blocks
==10668==         suppressed: 0 bytes in 0 blocks
==10668== 
==10668== For counts of detected and suppressed errors, rerun with: -v
==10668== Use --track-origins=yes to see where uninitialised values come from
==10668== ERROR SUMMARY: 37 errors from 15 contexts (suppressed: 0 from 0)

2.2.3 memcheck檢測結果分析

memcheck的LEAK SUMMARY輸出結果將內存泄漏分爲如下幾種狀況:
  definitely lost:明確地已經泄漏了,由於在程序運行完的時候,沒有指針指向它, 指向它的指針在程序中丟失了
  indirectly lost:間接丟失。當使用了含有指針成員的類或結構時可能會報這個錯誤。這類錯誤無需直接修復,他們老是與」definitely lost」一塊兒出現,只要修復」definitely lost」便可。
  possibly lost:發現了一個指向某塊內存中部的指針,而不是指向內存塊頭部。這種指針通常是原先指向內存塊頭部,後來移動到了內存塊的中部,還有可能該指針和該內存根本就沒有關係,檢測工具只是懷疑有內存泄漏。
  still reachable:能夠訪問,未丟失但也未釋放
  suppressed:已被解決。出現了內存泄露但系統自動處理了。能夠無視這類錯誤。
內存泄漏概述:

==10668== LEAK SUMMARY:
==10668==    definitely lost: 100 bytes in 1 blocks
==10668==    indirectly lost: 0 bytes in 0 blocks
==10668==      possibly lost: 0 bytes in 0 blocks
==10668==    still reachable: 0 bytes in 0 blocks
==10668==         suppressed: 0 bytes in 0 blocks

  此處只有100個字節的內存泄漏。

==10668== Invalid write of size 8
==10668==    at 0x4C3453F: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x40075D: stringcopy(char*) (gdbmem.cpp:13)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668==  Address 0x5204060 is 32 bytes inside a block of size 33 alloc'd

  根據錯誤提示,stringcopy 函數13行,即memset(pdst, 0, len 2);申請了len的數據長度,memset的時候卻使用了2len的數據長度,內存寫溢出了。

==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid write of size 1
==10668==    at 0x4C34558: memset (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x40075D: stringcopy(char*) (gdbmem.cpp:13)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668==  Address 0x5204080 is 16 bytes after a block of size 48 in arena "client"

   stringcopy 函數13行,即memset(pdst, 0, len2);申請了len的數據長度,memset的時候卻使用了2len的數據長度,內存寫溢出。相同語句的內存寫溢出,卻報了兩個錯誤,緣由筆者目前也尚未弄明白,若是有大蝦指點,不勝感激。

==10668== 
==10668== Invalid write of size 8
==10668==    at 0x4C326CB: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400778: stringcopy(char*) (gdbmem.cpp:14)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668==  Address 0x5204060 is 32 bytes inside a block of size 33 alloc'd
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid write of size 2
==10668==    at 0x4C32723: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400778: stringcopy(char*) (gdbmem.cpp:14)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668==  Address 0x5204080 is 16 bytes after a block of size 48 in arena "client"

  stringcopy 函數13行,即memcpy(pdst, psrc, len2);申請了len的數據長度,memset的時候卻使用了2len的數據長度,內存寫溢出。

==10668== 
this is a memory debug program!
arry[0]:1
arry[1]:2
arry[2]:3
arry[3]:4
arry[4]:5
arry[5]:6
arry[6]:7
arry[7]:8
arry[8]:9
arry[9]:10
arry[11]:-623874025
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E8890E: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Use of uninitialised value of size 8
==10668==    at 0x4E84711: _itoa_word (_itoa.c:180)
==10668==    by 0x4E8812C: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E84718: _itoa_word (_itoa.c:180)
==10668==    by 0x4E8812C: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E881AF: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E87C59: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)
==10668== 
==10668== Conditional jump or move depends on uninitialised value(s)
==10668==    at 0x4E87CE2: vfprintf (vfprintf.c:1631)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x4008E6: main (gdbmem.cpp:45)

  main函數45行,printf("%p", pwildptr);讀取未初始化的野指針

==10668== 
==10668== Invalid write of size 8
==10668==    at 0x4C326CB: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008FE: main (gdbmem.cpp:47)
==10668==  Address 0x5204040 is 0 bytes inside a block of size 33 free'd
==10668==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008D0: main (gdbmem.cpp:44)
==10668==  Block was alloc'd at
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid write of size 2
==10668==    at 0x4C32723: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008FE: main (gdbmem.cpp:47)
==10668==  Address 0x5204050 is 16 bytes inside a block of size 33 free'd
==10668==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008D0: main (gdbmem.cpp:44)
==10668==  Block was alloc'd at
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)

  main函數47行,memcpy(ptmp, ptmp2, 20);寫入已經釋放的內存

==10668== 
==10668== Invalid read of size 1
==10668==    at 0x4ED0760: strchrnul (strchr.S:24)
==10668==    by 0x4E87207: __find_specmb (printf-parse.h:108)
==10668==    by 0x4E87207: vfprintf (vfprintf.c:1312)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x40090F: main (gdbmem.cpp:48)
==10668==  Address 0x5204040 is 0 bytes inside a block of size 33 free'd
==10668==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008D0: main (gdbmem.cpp:44)
==10668==  Block was alloc'd at
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)
==10668== 
==10668== Invalid read of size 1
==10668==    at 0x4E8741A: vfprintf (vfprintf.c:1324)
==10668==    by 0x4E8F898: printf (printf.c:33)
==10668==    by 0x40090F: main (gdbmem.cpp:48)
==10668==  Address 0x5204040 is 0 bytes inside a block of size 33 free'd
==10668==    at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x4008D0: main (gdbmem.cpp:44)
==10668==  Block was alloc'd at
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400740: stringcopy(char*) (gdbmem.cpp:12)
==10668==    by 0x40087A: main (gdbmem.cpp:36)

  main函數47行,printf(ptmp);寫入已經釋放的內存

0x40097d==10668== 
==10668== FILE DESCRIPTORS: 3 open at exit.
==10668== Open file descriptor 2: /dev/pts/4
==10668==    <inherited from parent>
==10668== 
==10668== Open file descriptor 1: /dev/pts/4
==10668==    <inherited from parent>
==10668== 
==10668== Open file descriptor 0: /dev/pts/4
==10668==    <inherited from parent>

  linux爲了實現一切皆文件的設計哲學,不只將數據抽象成了文件,也將一切操做和資源抽象成了文件,好比說硬件設備,socket,磁盤,進程,線程等。
這樣的設計將系統的全部動做都統一塊兒來,實現了對系統的原子化操做,大大下降了維護和操做的難度。
  設備描述符,就是描述該文件數據設備的惟一標示,不一樣類型的文件,文件描述符也不同,以下所示:
clipboard.png

==10668== 
==10668== 
==10668== HEAP SUMMARY:
==10668==     in use at exit: 100 bytes in 1 blocks
==10668==   total heap usage: 3 allocs, 2 frees, 1,157 bytes allocated
==10668== 
==10668== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==10668==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==10668==    by 0x400888: main (gdbmem.cpp:38)
==10668==

  內存泄漏概述,3次內存分配,兩次釋放。已經有100個字節的內存已經肯定泄漏。泄漏的內存分配於38行,char ptmp2 = (char)malloc(100);至此,內存泄漏檢測完畢。

valgrind內存檢測解析

  valgrind對內存讀寫溢出,讀取未初始化的變量、指針、內存可以很好的檢測到,可是對於數組越界卻沒法檢測,這是由於memcheck並不對stack和全局數組進行越界檢查,因此沒法檢測出printarray中的內存訪問越界。

相關文章
相關標籤/搜索