Bagaimana Anda mendeteksi / menghindari Kebocoran memori dalam kode Anda (Tidak dikelola)? [Tutup]


125

Dalam kode C / C ++ yang tidak dikelola, praktik apa yang terbaik untuk mendeteksi kebocoran memori? Dan pedoman pengkodean yang harus dihindari? (Seolah itu sesederhana itu;)

Kami telah menggunakan sedikit cara konyol di masa lalu: memiliki peningkatan penghitung untuk setiap panggilan alokasi dan pengurangan memori saat membebaskan. Pada akhir program, nilai penghitung harus nol.

Saya tahu ini bukan cara yang bagus dan ada beberapa tangkapan. (Misalnya, jika Anda membebaskan memori yang dialokasikan oleh panggilan platform API, jumlah alokasi Anda tidak akan sama persis dengan jumlah membebaskan Anda. Tentu saja, maka kami menambah penghitung saat memanggil panggilan API yang mengalokasikan memori.)

Saya mengharapkan pengalaman, saran, dan mungkin beberapa referensi untuk alat yang menyederhanakan ini.


Dalam hal menghindari kebocoran, pos berikut memiliki beberapa saran: http://stackoverflow.com/questions/27492/c-memory-management
tonylo


Saya menggunakan ini dengan studio visual untuk mendeteksi kebocoran mem. codeproject.com/KB/applications/visualleakdetector.aspx
tiboo

1
Anda searh valgrin (untuk linux) atau deleaker (untuk windows), juga terlihat detektor kebocoran visual ...
John Smith

untuk menemukan kebocoran memori, periksa di sini: theunixshell.blogspot.com/2013/11/…
Vijay

Jawaban:


78

Jika kode C / C ++ Anda portabel untuk * nix, beberapa hal lebih baik daripada Valgrind .


1
Valgrind juga sekarang berfungsi pada OS X, jadi linux bukan satu-satunya pilihan Anda.
Michael Anderson

1
Valgrind untuk Linux (dan OS X). Jika Anda menggunakan windose - deleaker - yang terbaik dari semuanya!
John Smith

@JordiBunster: Bagus! Tapi berbasis runtime. Dengan basis kode besar (ditulis dalam huruf C dalam kasus), Anda terutama akan menguji program Anda untuk cara yang telah dirancang. Seorang penyerang dapat memerlukan beberapa jam berjam-jam untuk membaca kode untuk menemukan exploit kebocoran memori. Saya akan mengharapkan alat otomatis untuk analisis kode sumber mirip dengan apa yang ada untuk JavaScript.
user2284570

65

Jika Anda menggunakan Visual Studio, Microsoft menyediakan beberapa fungsi yang berguna untuk mendeteksi dan men-debug kebocoran memori.

Saya akan mulai dengan artikel ini: https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.140).aspx

Berikut ringkasan artikel-artikel tersebut. Pertama, sertakan tajuk ini:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

Maka Anda perlu memanggil ini ketika program Anda keluar:

_CrtDumpMemoryLeaks();

Atau, jika program Anda tidak keluar di tempat yang sama setiap kali, Anda dapat memanggil ini di awal program Anda:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

Sekarang ketika program keluar dari semua alokasi yang tidak gratis akan dicetak di Window Output bersama dengan file mereka dialokasikan dan terjadi alokasi.

Strategi ini berfungsi untuk sebagian besar program. Namun, menjadi sulit atau tidak mungkin dalam kasus-kasus tertentu. Menggunakan pustaka pihak ketiga yang melakukan beberapa inisialisasi saat startup dapat menyebabkan objek lain muncul di memori dump dan dapat membuat melacak kebocoran Anda sulit. Juga, jika ada kelas Anda memiliki anggota dengan nama yang sama dengan rutin alokasi memori (seperti malloc), makro debug CRT akan menyebabkan masalah.

Ada teknik lain yang dijelaskan dalam tautan MSDN yang dirujuk di atas yang dapat digunakan juga.


Catatan tentang metode ini: tampaknya ini hanya berfungsi jika Anda menggunakan C murni dengan malloc dan gratis. Laporan terperinci yang mencakup nomor baris tidak dibuat jika Anda menggunakan c ++ baru dan hapus.
Zach

2
@Zach: sebenarnya Anda bisa menjalankannya juga (untuk kode apa pun yang sebenarnya Anda kompilasi sendiri) - lihat jawaban yang diterima di social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/…
Roman Starkov

Apakah ini akan bekerja dalam mode rilis juga?
JV

1
@ user3152463 No. Tidak. Menurut dokumentasi, itu hanya akan berfungsi untuk membangun debug: msdn.microsoft.com/en-us/library/e5ewb1h3(v=vs.71).aspx
Dusty Campbell

Baris ini salah: #define CRTDBG_MAP_ALLOC Seharusnya: #define _CRTDBG_MAP_ALLOC
Fallso

37

Di C ++: gunakan RAII. Smart pointer seperti std::unique_ptr, std::shared_ptr, std::weak_ptradalah teman Anda.


1
dan std: vektor adalah pengganti yang bagus untuk ketika array (buffer) dideallocated dalam fungsi yang sama mereka dialokasikan.
KJAWolf

4
Setidaknya std :: auto_ptr dan boost :: shared_ptr masih rentan terhadap kebocoran.
Jasper Bekkers

5
Hanya jika Anda salah menggunakannya, meskipun saya harus mengakui bahwa untuk std :: auto_ptr menggunakannya dengan salah cukup mudah.
Leon Timmermans

2
Meskipun ini adalah saran yang baik untuk standar pengkodean, itu tidak menjawab pertanyaan. Bahkan menggunakan shared_ptr dapat menyebabkan kebocoran dengan ketergantungan melingkar. Dan Anda dapat memiliki "kebocoran" dengan strategi caching tanpa batas, yang berlaku bahkan untuk bahasa yang dikumpulkan sampah.
CashCow

@CashCow: Anda benar. Walaupun saya belum melihatnya dalam praktik, itu mungkin karena saya menggunakannya dengan hemat. Mengutip jawaban di bawah ini, "Gunakan pointer hanya ketika benar-benar diperlukan".
Leon Timmermans

28

Sebagai Pengembang C ++ inilah beberapa pedoman sederhana:

  1. Gunakan pointer hanya ketika benar-benar diperlukan
  2. Jika Anda membutuhkan pointer, klik dua kali periksa apakah SmartPointer kemungkinan
  3. Gunakan pola GRASP Creator .

Sedangkan untuk mendeteksi kebocoran memori secara pribadi, saya selalu menggunakan Visual Leak Detector dan merasa sangat berguna.


2
Visual Leak Detectore pindah ke situs baru vld.codeplex.com
KindDragon

VLD adalah detektor kebocoran yang BENAR-BENAR bagus - Saya sangat merekomendasikannya untuk semua orang yang menggunakan VC ++
Javid

1
+1 untuk poin # 1. Ini benar-benar hal mendasar. Sayangnya, menurut saya beberapa perpustakaan "C ++" terbesar cenderung menghindari alokasi stack dan / atau RAII demi Pointer Everywhere, seringkali tanpa alasan yang jelas. Jadi, mereka akhirnya menjadi 'C dengan Kelas', bukan C ++ yang sebenarnya.
underscore_d

16

Saya telah menggunakan DevStudio selama bertahun-tahun sekarang dan selalu membuat saya kagum betapa banyak programmer tidak tahu tentang alat analisis memori yang tersedia di pustaka run time debug. Berikut beberapa tautan untuk memulai:

Melacak Heap Allocation Requests - khususnya bagian tentang Nomor Permintaan Alokasi Unik

_CrtSetDbgFlag

_CrtSetBreakAlloc

Tentu saja, jika Anda tidak menggunakan DevStudio maka ini tidak akan sangat membantu.



7

Detektor Kebocoran Visual adalah alat yang sangat bagus, meskipun tidak mendukung panggilan pada runtime VC9 (misalnya MSVCR90D.DLL).


1
Alat ini sangat sempurna! Menghemat masalah untuk menggunakan _CrtDumpMemoryLeaks (); dan teman-teman, sebagaimana dijelaskan dalam MSDN. Hanya satu termasuk dan itu memaparkan segalanya! Bahkan bekerja di perpustakaan C lama!
m_pGladiator

Versi baru (untuk VS2013) ada di sini: vld.codeplex.com
Dženan

7

Microsoft VC ++ dalam mode debug menunjukkan kebocoran memori, meskipun tidak menunjukkan di mana kebocoran Anda.

Jika Anda menggunakan C ++ Anda selalu dapat menghindari menggunakan baru secara eksplisit: Anda memiliki vector, string, auto_ptr(pra C ++ 11; digantikan oleh unique_ptrC ++ 11), unique_ptr(C ++ 11) dan shared_ptr(C ++ 11) di gudang Anda.

Ketika hal baru tidak dapat dihindari, coba sembunyikan di konstruktor (dan sembunyikan hapus di destruktor); karya yang sama untuk API pihak ke-3.


1
dan jangan lupa aturan 3 atau 5 saat itu
Humam Helfawi

4

Ada berbagai pustaka "malloc" pengganti di luar sana yang akan memungkinkan Anda untuk memanggil fungsi di bagian akhir dan itu akan memberi tahu Anda tentang semua memori yang belum diolah, dan dalam banyak kasus, siapa yang malloced (atau yang baru) di tempat pertama .


4

Jika Anda menggunakan MS VC ++, saya sangat merekomendasikan alat gratis ini dari codeproject : leakfinder oleh Jochen Kalmbach.

Anda cukup menambahkan kelas ke proyek Anda, dan menelepon

InitAllocCheck(ACOutput_XML)
DeInitAllocCheck()

sebelum dan sesudah kode Anda ingin memeriksa kebocoran.

Setelah Anda membuat dan menjalankan kode, Jochen menyediakan alat GUI yang rapi di mana Anda dapat memuat file .xmlleaks yang dihasilkan, dan menavigasi melalui tumpukan panggilan di mana setiap kebocoran dihasilkan untuk memburu garis kode yang menyinggung.

PurifyPlus dari Rasional (sekarang dimiliki oleh IBM) mengilustrasikan kebocoran dengan cara yang serupa, tetapi saya menemukan alat leakfinder sebenarnya lebih mudah digunakan, dengan bonus itu tidak menelan biaya beberapa ribu dolar!


1
Saya memeriksa leakfinder dan terlihat oke, tetapi hanya FYI itu tidak akan berfungsi apa adanya untuk x64 karena berisi inline assembly.
Zach


3

Jika Anda menggunakan Visual Studio, mungkin layak melihat Bounds Checker . Ini tidak gratis, tetapi sudah sangat membantu dalam menemukan kebocoran dalam kode saya. Tidak hanya kebocoran memori, tetapi juga kebocoran sumber daya GDI, kesalahan penggunaan WinAPI, dan hal-hal lainnya. Itu bahkan akan menunjukkan kepada Anda di mana memori bocor diinisialisasi, sehingga lebih mudah untuk melacak kebocoran.


2

Saya pikir tidak ada jawaban mudah untuk pertanyaan ini. Bagaimana Anda benar-benar mendekati solusi ini tergantung pada kebutuhan Anda. Apakah Anda memerlukan solusi lintas platform? Apakah Anda menggunakan baru / hapus atau malloc / gratis (atau keduanya)? Apakah Anda benar-benar mencari hanya "kebocoran" atau apakah Anda menginginkan perlindungan yang lebih baik, seperti mendeteksi buffer overruns (atau underruns)?

Jika Anda bekerja di sisi windows, pustaka runtime MS debug memiliki beberapa fungsi pendeteksian debug dasar, dan seperti yang lain telah ditunjukkan, ada beberapa pembungkus yang dapat disertakan dalam sumber Anda untuk membantu dengan deteksi kebocoran. Menemukan paket yang dapat bekerja dengan baik baru / delete dan malloc / gratis jelas memberi Anda lebih banyak fleksibilitas.

Saya tidak cukup tahu tentang sisi unix untuk memberikan bantuan, meskipun sekali lagi, yang lain sudah.

Tapi selain deteksi kebocoran, ada gagasan mendeteksi korupsi memori melalui buffer overruns (atau underruns). Jenis fungsi debug ini menurut saya lebih sulit daripada deteksi kebocoran biasa. Jenis sistem ini juga lebih rumit jika Anda bekerja dengan objek C ++ karena kelas polimorfik dapat dihapus dengan berbagai cara yang menyebabkan kesulitan dalam menentukan pointer basis sebenarnya yang sedang dihapus. Saya tahu tidak ada sistem "bebas" yang baik yang melakukan perlindungan yang layak untuk overruns. kami telah menulis sebuah sistem (lintas platform) dan ternyata cukup menantang.


2

Saya ingin menawarkan sesuatu yang pernah saya gunakan di masa lalu: pemeriksa kebocoran dasar yang tingkat sumber dan cukup otomatis. Saya memberikan ini karena tiga alasan:

  1. Anda mungkin menemukan itu berguna.

  2. Meskipun ini agak krufty, aku tidak membiarkan itu membuatku malu.

  3. Meskipun itu terkait dengan beberapa kait win32, itu seharusnya mudah diatasi.

Ada beberapa hal yang Anda harus berhati-hati ketika menggunakannya: jangan melakukan apa pun yang perlu bersandar pada newkode yang mendasarinya, waspadalah terhadap peringatan tentang kasus yang mungkin terlewat di bagian atas leakcheck.cpp, sadarilah bahwa jika Anda menghidupkan pada (dan memperbaiki masalah apa pun dengan) kode yang melakukan dump gambar, Anda dapat menghasilkan file besar.

Desain ini dimaksudkan untuk memungkinkan Anda menghidupkan dan mematikan checker tanpa mengkompilasi ulang semua yang menyertakan headernya. Sertakan leakcheck.h di mana Anda ingin melacak pengecekan dan membangun kembali satu kali. Setelah itu, kompilasi leakcheck.cpp dengan atau tanpa LEAKCHECK # define'd lalu relink untuk menghidupkan dan mematikannya. Termasuk unleakcheck.h akan mematikannya secara lokal di file. Dua makro disediakan: CLEARALLOCINFO () akan menghindari melaporkan file dan baris yang sama secara tidak tepat ketika Anda melintasi kode alokasi yang tidak termasuk leakcheck.h. ALLOCFENCE () hanya menghapus satu baris dalam laporan yang dihasilkan tanpa melakukan alokasi apa pun.

Sekali lagi, tolong sadari bahwa saya belum pernah menggunakan ini dalam beberapa saat dan Anda mungkin harus bekerja sedikit dengannya. Saya menjatuhkannya untuk menggambarkan ide itu. Jika ternyata ada minat yang cukup, saya bersedia mengerjakan contoh, memperbarui kode dalam proses, dan mengganti konten URL berikut dengan sesuatu yang lebih bagus yang mencakup daftar berwarna sintaksis.

Anda dapat menemukannya di sini: http://www.cse.ucsd.edu/~tkammeye/leakcheck.html


2

Untuk Linux: Coba Google Perftools

Ada banyak alat yang melakukan alokasi / penghitungan gratis yang serupa, kelebihan dari Goolge Perftools:

  • Cukup cepat (dibandingkan dengan valgrind: sangat cepat)
  • Hadir dengan tampilan grafis yang bagus dari hasil
  • Memiliki kemampuan bermanfaat lainnya: profil cpu, profil penggunaan memori ...


2

Pertahanan terbaik terhadap kebocoran adalah struktur program yang meminimalkan penggunaan malloc. Ini tidak hanya baik dari perspektif pemrograman, tetapi juga meningkatkan kinerja dan pemeliharaan. Saya tidak berbicara tentang menggunakan hal-hal lain sebagai ganti malloc, tetapi dalam hal menggunakan kembali objek dan menjaga tab yang sangat eksplisit pada semua objek yang dilewatkan daripada mengalokasikan secara sembarangan seperti yang sering digunakan dalam bahasa dengan pengumpul sampah seperti Jawa.

Misalnya, program yang saya kerjakan memiliki banyak objek bingkai yang mewakili data gambar. Setiap objek frame memiliki sub-data, yang membebaskan frame destructor. Program menyimpan daftar semua frame yang dialokasikan, dan ketika itu membutuhkan yang baru, memeriksa daftar objek frame yang tidak digunakan untuk melihat apakah ia dapat menggunakan kembali yang sudah ada daripada mengalokasikan yang baru. Pada shutdown, itu hanya berulang melalui daftar, membebaskan semuanya.


2

Saya akan merekomendasikan menggunakan Memory Validator dari verifikasi perangkat lunak. Alat ini terbukti merupakan bantuan yang tak ternilai untuk membantu saya melacak kebocoran memori dan meningkatkan manajemen memori aplikasi yang sedang saya kerjakan.

Alat yang sangat lengkap dan cepat.


Memory Validator juga menyediakan nama file dan nomor baris untuk C # yang memanggil kode asli Anda. versi x64 dalam versi beta
Stephen Kellett

2

Apakah Anda menghitung allocs dan membebaskan dengan interpolasi fungsi syscall Anda sendiri yang merekam panggilan dan kemudian meneruskan panggilan ke fungsi yang sebenarnya?

Ini adalah satu-satunya cara Anda dapat melacak panggilan yang berasal dari kode yang belum Anda tulis.

Lihatlah halaman manual untuk ld.so. Atau ld.so.1 pada beberapa sistem.

Juga lakukan Google LD_PRELOAD dan Anda akan menemukan beberapa artikel menarik yang menjelaskan teknik ini di www.itworld.com.


1

Setidaknya untuk MS VC ++, pustaka C Runtime memiliki beberapa fungsi yang saya temukan sangat membantu di masa lalu. Periksa bantuan MSDN untuk _Crt*fungsinya.


1

Mmgr Paul Nettle adalah alat favorit saya sejak lama. Anda menyertakan mmgr.h dalam file sumber Anda, menentukan TEST_MEMORY, dan memberikan file teks penuh masalah memori yang terjadi selama menjalankan aplikasi Anda.


1

Pedoman Pengodean Umum:

  • Sumber daya harus dialokasikan pada "lapisan" yang sama (fungsi / kelas / perpustakaan) di mana mereka dialokasikan.
  • Jika ini tidak memungkinkan, coba gunakan beberapa deallokasi otomatis (tingkatkan pointer bersama ...)

1

Alat debugging memori bernilai emas, tetapi selama bertahun-tahun saya telah menemukan bahwa dua ide sederhana dapat digunakan untuk mencegah sebagian besar kebocoran memori / sumber daya dikodekan.

  1. Tulis kode rilis segera setelah menulis kode akuisisi untuk sumber daya yang ingin Anda alokasikan. Dengan metode ini lebih sulit untuk "dilupakan" dan dalam beberapa hal memaksa seseorang untuk secara serius memikirkan siklus sumber daya yang digunakan di muka alih-alih sebagai tambahan.

  2. Gunakan pengembalian sesedikit mungkin. Apa yang dialokasikan seharusnya hanya dibebaskan di satu tempat jika memungkinkan. Jalur bersyarat antara perolehan sumber daya dan pelepasan harus dirancang sesederhana dan sejelas mungkin.


1

Di bagian atas daftar ini (ketika saya membacanya) adalah valgrind. Valgrind sangat baik jika Anda dapat mereproduksi kebocoran pada sistem pengujian. Saya telah menggunakannya dengan sukses besar.

Bagaimana jika Anda baru saja memperhatikan bahwa sistem produksinya bocor sekarang dan Anda tidak tahu bagaimana cara mereproduksinya dalam pengujian? Beberapa bukti tentang apa yang salah ditangkap dalam keadaan sistem produksi itu, dan mungkin cukup untuk memberikan wawasan tentang di mana masalahnya sehingga Anda dapat memperbanyaknya.

Di situlah pengambilan sampel Monte Carlo. Baca artikel blog Raymond Chen, "Cara orang miskin mengidentifikasi kebocoran memori" dan kemudian periksa implementasi saya (menganggap Linux, hanya diuji pada x86 dan x86-64)

http://github.com/tialaramex/leakdice/tree/master


1

Bekerja pada sistem operasi ponsel Motorola, kami membajak perpustakaan alokasi memori untuk mengamati semua alokasi memori. Ini membantu untuk menemukan banyak masalah dengan alokasi memori. Karena pencegahan lebih baik daripada mengobati, saya akan merekomendasikan untuk menggunakan alat analisis statis seperti Klockwork atau PC-Lint


belat adalah pengganti yang lebih baru untuk serat.
Mark Kegel

@ user14788: Produk PC-Lint Gimpel jauh lebih modern daripada Unix lama lint. Ini memiliki banyak pemeriksaan khusus untuk C ++, yang afaik belat tidak. Lihat tautan dalam jawaban (yang saya beri nama baru dari Lint ke PC-Lint).
Dan

0

Valgrind adalah opsi yang bagus untuk Linux. Di bawah MacOS X, Anda dapat mengaktifkan pustaka MallocDebug yang memiliki beberapa opsi untuk men-debug masalah alokasi memori (lihat manual malloc, bagian "LINGKUNGAN" memiliki detail yang relevan). OS X SDK juga menyertakan alat yang disebut MallocDebug (biasanya dipasang di / Developer / Applications / Performance Tools /) yang dapat membantu Anda memantau penggunaan dan kebocoran.



0

Pengganti malloc, calloc, dan reallloc yang bagus adalah rmdebug, cukup mudah digunakan. Jauh lebih cepat untuk melakukan valgrind, sehingga Anda dapat menguji kode Anda secara luas. Tentu saja ada beberapa kerugian, begitu Anda menemukan kebocoran, Anda mungkin masih perlu menggunakan valgrind untuk menemukan di mana kebocoran itu muncul dan Anda hanya dapat menguji mallocs yang Anda lakukan secara langsung. Jika lib bocor karena Anda salah menggunakannya, rmdebug tidak akan menemukannya.

http://www.hexco.de/rmdebug/


0

Sebagian besar memori profiler memperlambat aplikasi Windows kompleks saya yang besar ke titik di mana hasilnya tidak berguna. Ada satu alat yang berfungsi dengan baik untuk menemukan kebocoran di aplikasi saya: UMDH - http://msdn.microsoft.com/en-us/library/ff560206%28VS.85%29.aspx


Saya tidak melihat mengapa perlambatan membuat hasil tidak berguna. Tentunya memori yang bocor bocor terlepas dari kecepatan program berjalan. Intinya alat ini adalah mencari kebocoran, jadi di mana masalahnya? Apakah itu berjalan sangat lambat sehingga Anda tidak bisa secara fisik mendapatkannya untuk menutupi semua jalur kode untuk membuat profil?
underscore_d

-1

Mtrace tampaknya menjadi standar bawaan untuk linux. Langkah-langkahnya adalah:

  1. mengatur variabel lingkungan MALLOC_TRACE di bash
    MALLOC_TRACE = / tmp / mtrace.dat
    ekspor MALLOC_TRACE;
  2. Menambahkan #sertakan <mcheck.h> ke bagian atas file sumber utama Anda
  3. Tambahkan mtrace (); di awal main dan muntrace ();di bagian bawah (sebelum pernyataan pengembalian)
  4. kompilasi program Anda dengan saklar -g untuk informasi debug
  5. jalankan program anda
  6. tampilkan info kebocoran dengan
    mtrace your_prog_exe_name /tmp/mtrace.dat
    (saya harus menginstal skrip perl mtrace terlebih dahulu pada sistem fedora saya dengan yum install glibc_utils   )

mtrace tidak super membantu untuk C ++
Erin
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.