日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C/C++内存检测工具valgrind--memcheck

發布時間:2023/12/3 c/c++ 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C/C++内存检测工具valgrind--memcheck 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Valgrind簡介

Valgrind是運行在Linux上的一套基于仿真技術的程序調試和分析工具,作者是獲得過Google-O’Reilly開源大獎的Julian Seward,它包含一個內核 —— 一個軟件合成的CPU,和一系列的小工具,每個工具都可以完成一項任務──調試,分析,或測試等,內存檢測,我們可以使用它的工具:Memcheck。

?

Valgrind安裝

方法 1. valgrind官網:http://valgrind.org下載

方法 2. Ubuntu: sudo apt-get install valgrind

?

Memcheck的檢測范圍

它可以用來檢測c/c++程序中出現的內存問題,所有對內存的讀寫都會被檢測到,一切對malloc()/free()/new/delete的調用都會被捕獲。所以,它能檢測以下問題:
1). 對未初始化內存的使用;

2). 讀/寫釋放后的內存塊;

3). 讀/寫超出malloc等分配的動態內存范圍;

4). 讀/寫不適當的棧中內存塊;

5). 內存泄漏,指向一塊內存的指針永遠丟失;

6). 不正確的malloc/free或new/delete匹配;

7). memcpy()相關函數中的dst和src指針重疊問題。

?

Memcheck檢測使用步驟及注意事項

1、在編譯程序的時候打開調試模式(gcc編譯器的-g選項),以便顯示行號,編譯時去掉-O1 -O2等優化選項;檢查的是C++程序的時候,考慮加上選項: -fno- inline ,這樣它函數調用鏈會很清晰。

2、執行:valgrind --tool=memcheck --leak-check=full --log-file=./log.txt ./YourProgram

3、程序運行結束,查看 log.txt 中的結果。

結果分析:

Valgrind(memcheck)包含這7類錯誤,黑體為一般的錯誤提示:

1、illegal read/illegal write errors 非法讀取/非法寫入錯誤

2、use of uninitialised values 使用未初始化的區域

3、use of uninitialised or unaddressable values in system calls 系統調用時使用了未初始化或不可尋址的地址

4、illegal frees 非法的釋放

5、when a heap block is freed with an inappropriate deallocation function 分配和釋放函數不匹配

6、overlapping source and destination blocks 源和目的內存塊重疊

7、memory leak detection 內存泄漏檢測

? 7.1 Still reachable 內存指針還在還有機會使用或者釋放,指針指向的動態內存還沒有被釋放就退出了

? 7.2 Definitely lost 確定的內存泄露,已經不能夠訪問這塊內存

? 7.3 Indirectly lost 指向該內存的指針都位于內存泄露處

? 7.4 Possibly lost 可能的內存泄露,仍然存在某個指針能夠訪問某塊內存,但該指針指向的已經不是該內存首位置

? 7.5 Suppressed 某些庫產生的錯誤不予以提示,這些錯誤會被統計到suppressed項目

?

測試案例:

最近剛剛用最小堆實現了一個定時容器,寫完之后就使用Valgrind的memcheck工具檢測了一些內存,log日志如下:

==38716== Memcheck, a memory error detector ==38716== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==38716== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==38716== Command: ./test_heap_timer_new ==38716== Parent PID: 17817 ==38716== ==38716== Invalid write of size 4 ==38716== at 0x10BFF8: HeapTimer<Event>::setPos(int) (heap_timer.hpp:59) ==38716== by 0x10BF30: HeapTimerContainer<Event>::percolateDown(int) (heap_timer.hpp:334) ==38716== by 0x10BAD3: HeapTimerContainer<Event>::popTimer() (heap_timer.hpp:300) ==38716== by 0x10B79C: HeapTimerContainer<Event>::tick() (heap_timer.hpp:196) ==38716== by 0x10B34C: main (test_heap_timer_new.cpp:307) ==38716== Address 0x4db2478 is 24 bytes inside a block of size 32 free'd ==38716== at 0x483D1CF: operator delete(void*, unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==38716== by 0x10BA8B: HeapTimerContainer<Event>::popTimer() (heap_timer.hpp:296) ==38716== by 0x10B79C: HeapTimerContainer<Event>::tick() (heap_timer.hpp:196) ==38716== by 0x10B34C: main (test_heap_timer_new.cpp:307) ==38716== Block was alloc'd at ==38716== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so) ==38716== by 0x10B808: HeapTimerContainer<Event>::addTimer(long) (heap_timer.hpp:212) ==38716== by 0x10AC77: acceptConn(Event*, ITimerContainer<Event>*) (test_heap_timer_new.cpp:175) ==38716== by 0x10B2B5: main (test_heap_timer_new.cpp:293) ==38716== ==38716== ==38716== HEAP SUMMARY: ==38716== in use at exit: 0 bytes in 0 blocks ==38716== total heap usage: 10 allocs, 10 frees, 78,304 bytes allocated ==38716== ==38716== All heap blocks were freed -- no leaks are possible ==38716== ==38716== For lists of detected and suppressed errors, rerun with: -s ==38716== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

可以看到有一個4字節的無效內存寫入,是在HeapTimer::setPos(int) (heap_timer.hpp:59)里面,我找了半天,最終發現了原因。

原代碼鏈接:高性能定時器1——最小堆實現_Peerless__的博客-CSDN博客

代碼如下:

template <typename _UData> void HeapTimerContainer<_UData>::tick() {std::cout << "----------tick----------" << std::endl;HeapTimer<_UData> *tmp = _array[0];time_t cur = getMSec();// 循環處理到期的定時器while(!isEmpty()){if(!tmp){break;}// 如果定時器沒到期,則退出循環if(tmp->getExpire() > cur){break;}tmp->handleTimeOut();// 將堆頂元素刪除,同時生成新的堆頂定時器popTimer();tmp = _array[0];} }template <typename _UData> void HeapTimerContainer<_UData>::popTimer() {if(isEmpty()){return;}if(_array[0]){delete _array[0];// 將原來的堆頂元素替換為堆數組中最后一個元素_array[0] = _array[--_size];// 對新的堆頂元素執行下濾操作percolateDown(0);} }// 最小堆的下濾操作,它確保數組中以第hole個節點作為根的子樹擁有最小堆性質 template <typename _UData> void HeapTimerContainer<_UData>::percolateDown(int hole) { /* if(_size == 0){return;}*/HeapTimer<_UData> *temp = _array[hole];int child = 0;for(; ((hole * 2 + 1) <= _size - 1); hole = child){child = hole * 2 + 1;if((child < (_size - 1)) && (_array[child + 1]->getExpire() < _array[child]->getExpire())){child++;}if(_array[child]->getExpire() < temp->getExpire()){_array[hole] = _array[child];_array[hole]->setPos(hole); // 調整定時器的位置時,重新設置timer中pos保存的其在數組中的位置}else {break;}}_array[hole] = temp;_array[hole]->setPos(hole); }

上面代碼的邏輯是,tick函數被調用就會從最小堆中取出最近要超時的定時器(也就是堆頂元素),檢查是否超時,如果超時就執行回調函數,然后調用popTimer彈出堆頂元素。在popTimer中delete掉了剛超時的定時器,并將堆數組中最后一個元素放到堆頂,然后調用percolateDown來調整最小堆。Valgrind生成的日志中提示在HeapTimer::setPos(int) (heap_timer.hpp:59)出錯了。后來發現,如果堆中只有一個元素,這段代碼_array[0] = _array[–_size];也就變成了_array[0] = _array[0];然后就是在percolateDown函數中對已經delete掉的對象調用了setPos函數。也就是使用了已經delete掉的對象,但是程序運行的時候竟然沒有崩潰,這是個挺大的隱患的,沒有崩潰更為恐怖,因為可能下一次就要崩潰。解決方案就是在percolateDown函數中加一個數組是否為空的判斷,如果為空直接返回就好了。

總結

以上是生活随笔為你收集整理的C/C++内存检测工具valgrind--memcheck的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。