ubuntu 上使用valgrind

KingsLanding發表於2014-08-09

  Valgrind是一個GPL的軟體,用於Linux(For x86, amd64 and ppc32)程式的記憶體除錯和程式碼剖析。你可以在它的環境中執行你的程式來監視記憶體的使用情況,比如C 語言中的malloc和free或者 C++中的new和 delete。使用Valgrind的工具包,你可以自動的檢測許多記憶體管理和執行緒的bug,避免花費太多的時間在bug尋找上,使得你的程式更加穩固。

  Valgrind的主要功能
  Valgrind工具包包含多個工具,如Memcheck,Cachegrind,Helgrind, Callgrind,Massif。下面分別介紹個工具的作用:

Memcheck 工具主要檢查下面的程式錯誤:

  1.使用未初始化的記憶體 (Use of uninitialised memory)
  2.使用已經釋放了的記憶體 (Reading/writing memory after it has been free’d)
  3.使用超過 malloc分配的記憶體空間(Reading/writing off the end of malloc’d blocks)
  4.對堆疊的非法訪問 (Reading/writing inappropriate areas on the stack)
  5.申請的空間是否有釋放 (Memory leaks – where pointers to malloc’d blocks are lost forever)
  6.malloc/free/new/delete申請和釋放記憶體的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
  7.src和dst的重疊(Overlapping src and dst pointers in memcpy() and related functions)
Callgrind
  Callgrind收集程式執行時的一些資料,函式呼叫關係等資訊,還可以有選擇地進行cache 模擬。在執行結束時,它會把分析資料寫入一個檔案。callgrind_annotate可以把這個檔案的內容轉化成可讀的形式。

Cachegrind
它模擬 CPU中的一級快取I1,D1和L2二級快取,能夠精確地指出程式中 cache的丟失和命中。如果需要,它還能夠為我們提供cache丟失次數,記憶體引用次數,以及每行程式碼,每個函式,每個模組,整個程式產生的指令數。這對優化程式有很大的幫助。

Helgrind
  它主要用來檢查多執行緒程式中出現的競爭問題。Helgrind 尋找記憶體中被多個執行緒訪問,而又沒有一貫加鎖的區域,這些區域往往是執行緒之間失去同步的地方,而且會導致難以發掘的錯誤。Helgrind實現了名為” Eraser” 的競爭檢測演算法,並做了進一步改進,減少了報告錯誤的次數。

Massif
  堆疊分析器,它能測量程式在堆疊中使用了多少記憶體,告訴我們堆塊,堆管理塊和棧的大小。Massif能幫助我們減少記憶體的使用,在帶有虛擬記憶體的現代系統中,它還能夠加速我們程式的執行,減少程式停留在交換區中的機率。

Ubuntu 安裝valgrind:

#> sudo apt-get install valgrind

valgrind 使用:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{

    char *ptr = (char *)malloc(1024);
    
    ptr[1024] = 0; //

    memcpy(ptr+1, ptr, 100);

    char ch = ptr[1024];

    free(ptr);
    free(ptr);

    char *ptr1;
    *ptr1 = 'a';

    char *ptr2 = (char *)malloc(1024);

    return 0;
}

#> valgrind --tool=memcheck --leak-check=yes ./valgTest

  注意在編譯程式的時候加上-g選項,列印錯誤資訊的時候會給出行號。上面的執行結果給出了六個錯誤。

  下面看一個多執行緒競爭的情況:

#include <pthread.h>
#include <stdio.h>
 
int a = 0;
 
void* child_fn (void* arg)
{
         a++;
         return NULL;
}
 
int main () 
{
         pthread_t child;
         pthread_create(&child,NULL, child_fn, NULL);
         a++;
         pthread_join(child,NULL);
         return 0;
}

 

zhuyp@ubuntu:~/valgrind$ valgrind --tool=helgrind ./helTest
==5639== Helgrind, a thread error detector
==5639== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
==5639== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==5639== Command: ./helTest
==5639==
==5639== ---Thread-Announcement------------------------------------------
==5639==
==5639== Thread #1 is the program's root thread
==5639==
==5639== ---Thread-Announcement------------------------------------------
==5639==
==5639== Thread #2 was created
==5639== at 0x51562CE: clone (clone.S:74)
==5639== by 0x4E44199: do_clone.constprop.3 (createthread.c:75)
==5639== by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (createthread.c:245)
==5639== by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5639== by 0x40068D: main (helTest.c:15)
==5639==
==5639== ----------------------------------------------------------------
==5639==
==5639== Possible data race during read of size 4 at 0x60104C by thread #1
==5639== Locks held: none
==5639== at 0x40068E: main (helTest.c:16)
==5639==
==5639== This conflicts with a previous write of size 4 by thread #2
==5639== Locks held: none
==5639== at 0x40065E: child_fn (helTest.c:8)
==5639== by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5639== by 0x4E45181: start_thread (pthread_create.c:312)
==5639== by 0x515630C: clone (clone.S:111)
==5639==
==5639== ----------------------------------------------------------------
==5639==
==5639== Possible data race during write of size 4 at 0x60104C by thread #1
==5639== Locks held: none
==5639== at 0x400697: main (helTest.c:16)
==5639==
==5639== This conflicts with a previous write of size 4 by thread #2
==5639== Locks held: none
==5639== at 0x40065E: child_fn (helTest.c:8)
==5639== by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5639== by 0x4E45181: start_thread (pthread_create.c:312)
==5639== by 0x515630C: clone (clone.S:111)
==5639==
==5639==
==5639== For counts of detected and suppressed errors, rerun with: -v
==5639== Use --history-level=approx or =none to gain increased speed, at
==5639== the cost of reduced accuracy of conflicting-access information
==5639== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

 前面寫過一個使用coredump除錯死鎖的方法,這裡使用valgrind 的 helgrind 工具也可以檢查出死鎖問題。

#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
using namespace std;

mutex m1,m2;


void func_2()
{
    m2.lock();
    cout<< "about to dead_lock"<<endl;
    m1.lock();
    
}

void func_1()
{
    m1.lock();
    
    chrono::milliseconds dura( 1000 );// delay to trigger dead_lock
    this_thread::sleep_for( dura );
        
    m2.lock();
    
}


int main()
{

    thread t1(func_1);

    thread t2(func_2);
    
    t1.join();
    t2.join();
    return 0;

}

 

zhuyp@ubuntu:~/valgrind$ g++ -Wall dead_lock_demo.cpp -o dead_lock_demo -g -std=c++11 -lpthread
zhuyp@ubuntu:~/valgrind$ valgrind --tool=helgrind ./dead_lock_demo
==5646== Helgrind, a thread error detector
==5646== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
==5646== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==5646== Command: ./dead_lock_demo
==5646==
about to dead_lock  // 執行到這裡,Ctrl + C 結束程式,則列印出如下資訊
^C==5646== ---Thread-Announcement------------------------------------------ 
==5646==
==5646== Thread #2 was created
==5646== at 0x56702CE: clone (clone.S:74)
==5646== by 0x4E44199: do_clone.constprop.3 (createthread.c:75)
==5646== by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (createthread.c:245)
==5646== by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5646== by 0x510CE3E: std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==5646== by 0x401789: std::thread::thread<void (&)()>(void (&)()) (thread:135)
==5646== by 0x40112D: main (dead_lock_demo.cpp:33)
==5646==
==5646== ----------------------------------------------------------------
==5646==
==5646== Thread #2: Exiting thread still holds 1 lock
==5646== at 0x4E4BF2C: __lll_lock_wait (lowlevellock.S:135)
==5646== by 0x4E47656: _L_lock_909 (pthread_mutex_lock.c:151)
==5646== by 0x4E4747E: pthread_mutex_lock (pthread_mutex_lock.c:79)
==5646== by 0x4C32072: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5646== by 0x40101B: __gthread_mutex_lock(pthread_mutex_t*) (gthr-default.h:748)
==5646== by 0x401421: std::mutex::lock() (mutex:134)
==5646== by 0x401111: func_1() (dead_lock_demo.cpp:25)
==5646== by 0x40278C: void std::_Bind_simple<void (*())()>::_M_invoke<>(std::_Index_tuple<>) (functional:1732)
==5646== by 0x4026E6: std::_Bind_simple<void (*())()>::operator()() (functional:1720)
==5646== by 0x40267F: std::thread::_Impl<std::_Bind_simple<void (*())()> >::_M_run() (thread:115)
==5646== by 0x510CBEF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==5646== by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5646==
==5646== ---Thread-Announcement------------------------------------------
==5646==
==5646== Thread #3 was created
==5646== at 0x56702CE: clone (clone.S:74)
==5646== by 0x4E44199: do_clone.constprop.3 (createthread.c:75)
==5646== by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (createthread.c:245)
==5646== by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5646== by 0x510CE3E: std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==5646== by 0x401789: std::thread::thread<void (&)()>(void (&)()) (thread:135)
==5646== by 0x40113E: main (dead_lock_demo.cpp:35)
==5646==
==5646== ----------------------------------------------------------------
==5646==
==5646== Thread #3: Exiting thread still holds 1 lock
==5646== at 0x4E4BF2C: __lll_lock_wait (lowlevellock.S:135)
==5646== by 0x4E47656: _L_lock_909 (pthread_mutex_lock.c:151)
==5646== by 0x4E4747E: pthread_mutex_lock (pthread_mutex_lock.c:79)
==5646== by 0x4C32072: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5646== by 0x40101B: __gthread_mutex_lock(pthread_mutex_t*) (gthr-default.h:748)
==5646== by 0x401421: std::mutex::lock() (mutex:134)
==5646== by 0x4010DF: func_2() (dead_lock_demo.cpp:14)
==5646== by 0x40278C: void std::_Bind_simple<void (*())()>::_M_invoke<>(std::_Index_tuple<>) (functional:1732)
==5646== by 0x4026E6: std::_Bind_simple<void (*())()>::operator()() (functional:1720)
==5646== by 0x40267F: std::thread::_Impl<std::_Bind_simple<void (*())()> >::_M_run() (thread:115)
==5646== by 0x510CBEF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==5646== by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5646==
==5646==
==5646== For counts of detected and suppressed errors, rerun with: -v
==5646== Use --history-level=approx or =none to gain increased speed, at
==5646== the cost of reduced accuracy of conflicting-access information
==5646== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 1 from 1)

吐槽一下,剛剛在Linux操作並編輯該博文,各種不適應啊,還是換到Windows下來編輯要方便些。。。

 

相關文章