การสำรวจตัวตรวจสอบการรั่วของหน่วยความจำอัตโนมัติ
ในคำตอบนี้ฉันเปรียบเทียบตัวตรวจสอบการรั่วไหลของหน่วยความจำที่แตกต่างกันหลายอย่างในตัวอย่างง่าย ๆ ที่จะเข้าใจหน่วยความจำรั่ว
ก่อนอื่นให้ดูตารางขนาดใหญ่นี้ในวิกิพีเดีย ASan ซึ่งเปรียบเทียบเครื่องมือทั้งหมดที่มนุษย์รู้จัก https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06210f759fec97066888e5f27c7e722832b0924
ตัวอย่างการวิเคราะห์จะเป็น:
main.c
#include <stdlib.h>
void * my_malloc(size_t n) {
return malloc(n);
}
void leaky(size_t n, int do_leak) {
void *p = my_malloc(n);
if (!do_leak) {
free(p);
}
}
int main(void) {
leaky(0x10, 0);
leaky(0x10, 1);
leaky(0x100, 0);
leaky(0x100, 1);
leaky(0x1000, 0);
leaky(0x1000, 1);
}
GitHub ต้นน้ำต้นน้ำ
เราจะพยายามดูว่าเครื่องมือที่แตกต่างกันทำอะไรอย่างชัดเจนชี้ให้เราไปที่การเรียกรั่ว
tcmalloc จาก gperftools โดย Google
https://github.com/gperftools/gperftools
การใช้งานบน Ubuntu 19.04:
sudo apt-get install google-perftools
gcc -ggdb3 -o main.out main.c -ltcmalloc
PPROF_PATH=/usr/bin/google-pprof \
HEAPCHECK=normal \
HEAPPROFILE=ble \
./main.out \
;
google-pprof main.out ble.0001.heap --text
เอาต์พุตของการรันโปรแกรมมีการวิเคราะห์การรั่วไหลของหน่วยความจำ:
WARNING: Perftools heap leak checker is active -- Performance may suffer
Starting tracking the heap
Dumping heap profile to ble.0001.heap (Exiting, 4 kB in use)
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 272 bytes in 2 objects
The 2 largest leaks:
Using local file ./main.out.
Leak of 256 bytes in 1 objects allocated from:
@ 555bf6e5815d my_malloc
@ 555bf6e5817a leaky
@ 555bf6e581d3 main
@ 7f71e88c9b6b __libc_start_main
@ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
@ 555bf6e5815d my_malloc
@ 555bf6e5817a leaky
@ 555bf6e581b5 main
@ 7f71e88c9b6b __libc_start_main
@ 555bf6e5808a _start
If the preceding stack traces are not enough to find the leaks, try running THIS shell command:
pprof ./main.out "/tmp/main.out.24744._main_-end.heap" --inuse_objects --lines --heapcheck --edgefraction=1e-10 --nodefraction=1e-10 --gv
If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more re
Exiting with error code (instead of crashing) because of whole-program memory leaks
และผลลัพธ์ของgoogle-pprof
การวิเคราะห์การใช้งานฮีปประกอบด้วย:
Using local file main.out.
Using local file ble.0001.heap.
Total: 0.0 MB
0.0 100.0% 100.0% 0.0 100.0% my_malloc
0.0 0.0% 100.0% 0.0 100.0% __libc_start_main
0.0 0.0% 100.0% 0.0 100.0% _start
0.0 0.0% 100.0% 0.0 100.0% leaky
0.0 0.0% 100.0% 0.0 100.0% main
ผลลัพธ์ชี้ไปที่สองในสามของการรั่วไหล:
Leak of 256 bytes in 1 objects allocated from:
@ 555bf6e5815d my_malloc
@ 555bf6e5817a leaky
@ 555bf6e581d3 main
@ 7f71e88c9b6b __libc_start_main
@ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
@ 555bf6e5815d my_malloc
@ 555bf6e5817a leaky
@ 555bf6e581b5 main
@ 7f71e88c9b6b __libc_start_main
@ 555bf6e5808a _start
ฉันไม่แน่ใจว่าทำไมคนที่สามไม่ปรากฏ
ไม่ว่าในกรณีใดมักเกิดการรั่วไหลเกิดขึ้นหลายครั้งและเมื่อฉันใช้มันในโครงการจริงฉันเพิ่งจบลงด้วยการชี้ไปที่ฟังก์ชั่นการรั่วไหลได้ง่ายมาก
ดังที่กล่าวไว้ในเอาต์พุตตัวเองสิ่งนี้ทำให้เกิดการดำเนินการช้าลงอย่างมาก
เอกสารเพิ่มเติมที่:
ดูเพิ่มเติมที่: วิธีใช้ TCMalloc
ทดสอบใน Ubuntu 19.04, google-perftools 2.5-2
ที่อยู่ Sanitizer (ASan) โดย Google
https://github.com/google/sanitizers
ก่อนหน้านี้กล่าวถึงที่: วิธีการค้นหาหน่วยความจำรั่วในรหัส C ++ / โครงการ? สิ่งที่ต้องทำเทียบกับ tcmalloc
สิ่งนี้ได้รวมเข้ากับ GCC แล้วดังนั้นคุณสามารถทำได้:
gcc -fsanitize=address -ggdb3 -o main.out main.c
./main.out
และเอาต์พุตการประมวลผล:
=================================================================
==27223==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 4096 byte(s) in 1 object(s) allocated from:
#0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
#1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
#2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
#3 0x55bf86c5f210 in main /home/ciro/test/main.c:20
#4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
Direct leak of 256 byte(s) in 1 object(s) allocated from:
#0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
#1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
#2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
#3 0x55bf86c5f1f2 in main /home/ciro/test/main.c:18
#4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
Direct leak of 16 byte(s) in 1 object(s) allocated from:
#0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
#1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
#2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
#3 0x55bf86c5f1d4 in main /home/ciro/test/main.c:16
#4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)
SUMMARY: AddressSanitizer: 4368 byte(s) leaked in 3 allocation(s).
ซึ่งระบุการรั่วไหลทั้งหมดอย่างชัดเจน ดี!
ASan ยังสามารถทำการตรวจสอบเด็ด ๆ อื่น ๆ เช่นการเขียนนอกขอบเขต: ตรวจพบการซ้อน
ทดสอบใน Ubuntu 19.04, GCC 8.3.0
valgrind
http://www.valgrind.org/
พูดถึงก่อนหน้านี้ที่: https://stackoverflow.com/a/37661630/895245
การใช้งาน:
sudo apt-get install valgrind
gcc -ggdb3 -o main.out main.c
valgrind --leak-check=yes ./main.out
เอาท์พุท:
==32178== Memcheck, a memory error detector
==32178== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32178== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==32178== Command: ./main.out
==32178==
==32178==
==32178== HEAP SUMMARY:
==32178== in use at exit: 4,368 bytes in 3 blocks
==32178== total heap usage: 6 allocs, 3 frees, 8,736 bytes allocated
==32178==
==32178== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==32178== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178== by 0x10915C: my_malloc (main.c:4)
==32178== by 0x109179: leaky (main.c:8)
==32178== by 0x1091B4: main (main.c:16)
==32178==
==32178== 256 bytes in 1 blocks are definitely lost in loss record 2 of 3
==32178== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178== by 0x10915C: my_malloc (main.c:4)
==32178== by 0x109179: leaky (main.c:8)
==32178== by 0x1091D2: main (main.c:18)
==32178==
==32178== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3
==32178== at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178== by 0x10915C: my_malloc (main.c:4)
==32178== by 0x109179: leaky (main.c:8)
==32178== by 0x1091F0: main (main.c:20)
==32178==
==32178== LEAK SUMMARY:
==32178== definitely lost: 4,368 bytes in 3 blocks
==32178== indirectly lost: 0 bytes in 0 blocks
==32178== possibly lost: 0 bytes in 0 blocks
==32178== still reachable: 0 bytes in 0 blocks
==32178== suppressed: 0 bytes in 0 blocks
==32178==
==32178== For counts of detected and suppressed errors, rerun with: -v
==32178== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
ดังนั้นจึงตรวจพบรอยรั่วทั้งหมดอีกครั้ง
ดูเพิ่มเติม: ฉันจะใช้ valgrind เพื่อค้นหาหน่วยความจำรั่วได้อย่างไร
ทดสอบใน Ubuntu 19.04, valgrind 3.14.0