Saya seorang programmer C ++ pada platform Windows. Saya menggunakan Visual Studio 2008.
Saya biasanya berakhir di kode dengan kebocoran memori.
Biasanya saya menemukan kebocoran memori dengan memeriksa kode, tetapi rumit dan tidak selalu merupakan pendekatan yang baik.
Karena saya tidak mampu membeli alat pendeteksi kebocoran memori berbayar, saya ingin kalian menyarankan cara terbaik untuk menghindari kebocoran memori.
- Saya ingin tahu bagaimana programmer dapat menemukan kebocoran memori.
- Apakah ada standar atau prosedur yang harus diikuti untuk memastikan tidak ada kebocoran memori dalam program?
c++
memory-leaks
Chris_vr
sumber
sumber
Jawaban:
Instruksi
Hal yang Anda Butuhkan
1
Pahami dasar-dasar operator. Operator C ++
new
mengalokasikan memori tumpukan. Thedelete
membebaskan Operator tumpukan memori. Untuk setiapnew
, Anda harus menggunakandelete
sehingga Anda membebaskan memori yang sama yang Anda alokasikan:2
Alokasikan kembali memori hanya jika Anda telah menghapus. Dalam kode di bawah ini,
str
dapatkan alamat baru dengan alokasi kedua. Alamat pertama hilang tanpa bisa diperbaiki, dan begitu juga 30 byte yang ditunjuknya. Sekarang tidak mungkin dibebaskan, dan Anda mengalami kebocoran memori:3
Lihat tugas penunjuk itu. Setiap variabel dinamis (memori yang dialokasikan pada heap) perlu dikaitkan dengan pointer. Ketika variabel dinamis menjadi terlepas dari penunjuknya, menjadi tidak mungkin untuk dihapus. Sekali lagi, ini menghasilkan kebocoran memori:
4
Hati-hati dengan petunjuk lokal. Pointer yang Anda nyatakan dalam suatu fungsi dialokasikan pada stack, tetapi variabel dinamis yang ditunjuknya dialokasikan pada heap. Jika Anda tidak menghapusnya, itu akan tetap ada setelah program keluar dari fungsi:
5
Perhatikan kurung kurawal setelah "hapus." Gunakan
delete
dengan sendirinya untuk membebaskan satu objek. Gunakandelete []
dengan tanda kurung siku untuk membebaskan array tumpukan. Jangan lakukan hal seperti ini:6
Jika kebocoran belum diizinkan - Saya biasanya mencari dengan deleaker (periksa di sini: http://deleaker.com ).
sumber
someFunction("some parameter")
saya harus menghapus"some parameter"
dalamsomeFunction
, setelah panggilan fungsi, atau ini secara otomatis dihapus?Anda dapat menggunakan beberapa teknik dalam kode Anda untuk mendeteksi kebocoran memori. Cara paling umum dan paling mudah untuk dideteksi adalah, tentukan makro katakan, DEBUG_NEW dan gunakan, bersama dengan makro yang sudah ditentukan seperti
__FILE__
dan__LINE__
untuk menemukan kebocoran memori dalam kode Anda. Makro yang telah ditentukan ini memberi tahu Anda file dan nomor baris kebocoran memori.DEBUG_NEW hanyalah MACRO yang biasanya didefinisikan sebagai:
Sehingga di mana pun Anda menggunakan
new
, itu juga dapat melacak file dan nomor baris yang dapat digunakan untuk menemukan kebocoran memori dalam program Anda.Dan
__FILE__
,__LINE__
adalah makro yang telah ditetapkan yang mengevaluasi masing-masing nama file dan nomor baris tempat Anda menggunakannya!Baca artikel berikut yang menjelaskan teknik menggunakan DEBUG_NEW dengan makro menarik lainnya, sangat indah:
Detektor Kebocoran Memori Cross-Platform
Dari Wikpedia ,
sumber
#define
akan mengacaukan kelebihan bebanoperator new
dan menghasilkan kesalahan kompilator. Bahkan jika Anda berhasil mengatasinya maka fungsi yang kelebihan beban tidak akan ditangani. Meskipun tekniknya bagus, terkadang dibutuhkan banyak perubahan kode.auto_ptr
tidak akan berfungsi dengan kontainer standar sepertistd::vector
,std::list
dll. Lihat ini: stackoverflow.com/questions/111478/…operator new
dan apa versi ini yang Anda gunakan?Ada beberapa teknik pemrograman terkenal yang akan membantu Anda meminimalkan risiko kebocoran memori secara langsung:
new
dandelete
selalu berpasangan, dan pastikan kode alokasi / deallokasi disebut berpasanganvector<T> t
dimanapun memungkinkan alih-alihT* t = new T[size]
sumber
Valgrind http://valgrind.org/
dan
GDB http://www.gnu.org/software/gdb/
sumber
gflags
utilitas untuk menghidupkan jejak tumpukan mode pengguna.UMDH
untuk mengambil beberapa snapshot dari memori program Anda. Ambil snapshot sebelum memori dialokasikan, dan ambil snapshot kedua setelah titik di mana Anda yakin bahwa program Anda memiliki memori yang bocor. Anda mungkin ingin menambahkan jeda atau konfirmasi dalam program Anda untuk memberi Anda kesempatan untuk menjalankanUMDH
dan mengambil snapshot.UMDH
lagi, kali ini dalam mode yang melakukan perbedaan antara dua foto. Ini kemudian akan menghasilkan laporan yang berisi tumpukan panggilan kebocoran memori yang diduga.gflags
pengaturan sebelumnya ketika Anda selesai.UMDH
akan memberi Anda lebih banyak informasi daripada tumpukan debug CRT karena memantau alokasi memori di seluruh proses Anda; bahkan dapat memberi tahu Anda jika komponen pihak ketiga bocor.sumber
Menjalankan "Valgrind" dapat:
1) Membantu Mengidentifikasi Kebocoran Memori - menunjukkan kepada Anda berapa banyak memori yang bocor yang Anda miliki, dan tunjukkan ke baris-baris dalam kode tempat memori yang bocor dialokasikan.
2) Tunjukkan upaya yang salah untuk membebaskan memori (mis. Panggilan yang salah
delete
)Petunjuk untuk menggunakan "Valgrind"
1) Dapatkan valgrind di sini .
2) Kompilasi kode Anda dengan
-g
bendera3) Dalam menjalankan shell Anda:
Di mana "myprog" adalah program yang dikompilasi dan
arg1
,arg2
argumen program Anda.4) Hasilnya adalah daftar panggilan ke
malloc
/new
yang tidak memiliki panggilan berikutnya untuk dihapus secara gratis.Sebagai contoh:
Memberitahu Anda di baris mana
malloc
(yang tidak dibebaskan) dipanggil.Sebagaimana ditunjukkan oleh orang lain, pastikan bahwa untuk setiap
new
/malloc
panggilan, Anda memilikidelete
/free
panggilan berikutnya .sumber
Jika Anda menggunakan gcc, tersedia gprof.
Beberapa menggunakan alat, beberapa melakukan apa yang Anda lakukan, bisa juga melalui tinjauan kode rekan
Bagi saya: setiap kali saya membuat objek yang dialokasikan secara dinamis, saya selalu meletakkan kode pembebasan setelah itu, lalu mengisi kode di antaranya. Ini akan baik-baik saja jika Anda yakin tidak akan ada pengecualian dalam kode di antaranya. Kalau tidak, saya menggunakan try-akhirnya (saya tidak sering menggunakan C ++).
sumber
Di studio visual, ada detektor built-in untuk kebocoran memori yang disebut C Runtime Library. Ketika program Anda keluar setelah fungsi utama kembali, CRT akan memeriksa tumpukan debug aplikasi Anda. jika Anda memiliki blok yang masih dialokasikan pada tumpukan debug, maka Anda memiliki kebocoran memori ..
Forum ini membahas beberapa cara untuk menghindari kebocoran memori di C / C ++ ..
sumber
Cari kode Anda untuk kemunculan
new
, dan pastikan semuanya terjadi dalam konstruktor dengan penghapusan yang cocok di destruktor. Pastikan bahwa ini adalah satu-satunya operasi melempar yang mungkin di konstruktor itu. Cara sederhana untuk melakukan ini adalah dengan membungkus semua pointerstd::auto_ptr
, atauboost::scoped_ptr
(tergantung pada apakah Anda perlu memindahkan semantik). Untuk semua kode di masa depan, pastikan saja bahwa setiap sumber daya dimiliki oleh objek yang membersihkan sumber daya di destruktornya. Jika Anda perlu memindahkan semantik maka Anda dapat memutakhirkan ke kompiler yang mendukung r-value reference (VS2010 menurut saya) dan membuat move constructor. Jika Anda tidak ingin melakukan itu maka Anda dapat menggunakan berbagai teknik rumit yang melibatkan penggunaan swap yang teliti, atau coba perpustakaan Boost.Move.sumber
scope_ptr
s, dan masing-masing diinisialisasi secara individual maka semua yang berhasil dibangun akan menghapus pointer mereka, dan yang lain belum akan memegang pointer ke memori yang dialokasikan. Saya akan memberikan contoh dalam beberapa jam ketika saya pulang dari kerja.Anda dapat menggunakan alat Valgrind untuk mendeteksi kebocoran memori.
Juga, untuk menemukan kebocoran pada fungsi tertentu, gunakan keluar (0) di akhir fungsi dan kemudian jalankan dengan Valgrind
sumber
Survei pemeriksa kebocoran memori otomatis
Dalam jawaban ini, saya membandingkan beberapa kebocoran kebocoran memori yang berbeda dalam contoh kebocoran memori yang mudah dimengerti.
Sebelum apa pun, lihat tabel besar ini di wiki ASan yang membandingkan semua alat yang diketahui oleh manusia: https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06210f759fec97066888e5f27c7e722832b0924
Contoh yang dianalisis adalah:
main.c
GitHub hulu .
Kami akan mencoba melihat seberapa jelas alat yang berbeda mengarahkan kami ke panggilan yang bocor.
tcmalloc dari gperftools oleh Google
https://github.com/gperftools/gperftools
Penggunaan di Ubuntu 19.04:
Output dari program yang dijalankan berisi analisis kebocoran memori:
dan output
google-pprof
berisi analisis penggunaan tumpukan:Output menunjukkan kita ke dua dari tiga kebocoran:
Saya tidak yakin mengapa yang ketiga tidak muncul
Bagaimanapun, ketika biasanya ketika sesuatu bocor, itu terjadi berkali-kali, dan ketika saya menggunakannya pada proyek nyata, saya akhirnya ditunjukkan ke fungsi bocor dengan sangat mudah.
Seperti yang disebutkan pada output itu sendiri, ini menyebabkan pelambatan eksekusi yang signifikan.
Dokumentasi lebih lanjut di:
Lihat juga: Cara Menggunakan TCMalloc?
Diuji di Ubuntu 19.04, google-perftools 2.5-2.
Address Sanitizer (ASan) juga oleh Google
https://github.com/google/sanitizers
Disebutkan sebelumnya di: Bagaimana menemukan kebocoran memori dalam suatu kode / proyek C ++? TODO vs tcmalloc.
Ini sudah terintegrasi ke dalam GCC, jadi Anda bisa melakukan:
dan output eksekusi:
yang secara jelas mengidentifikasi semua kebocoran. Bagus!
ASan juga dapat melakukan pemeriksaan keren lainnya seperti menulis di luar batas: Penghancuran tumpukan terdeteksi
Diuji di Ubuntu 19.04, GCC 8.3.0.
Valgrind
http://www.valgrind.org/
Sebelumnya disebutkan di: https://stackoverflow.com/a/37661630/895245
Pemakaian:
Keluaran:
Jadi sekali lagi, semua kebocoran terdeteksi.
Lihat juga: Bagaimana cara menggunakan valgrind untuk menemukan kebocoran memori?
Diuji di Ubuntu 19.04, valgrind 3.14.0.
sumber
Visual Leak Detector (VLD) adalah sistem deteksi kebocoran memori open-source gratis, kuat untuk Visual C ++.
Jika Anda hanya memiliki crash dumps, Anda dapat menggunakan
!heap -l
perintah Windbg , itu akan mendeteksi blok heap yang bocor. Lebih baik buka opsi gflags: "Buat basis data jejak jejak mode pengguna", maka Anda akan melihat tumpukan panggilan alokasi memori.sumber
MTuner adalah alat profil memori multi platform gratis, deteksi kebocoran, dan alat analisis yang mendukung kompiler MSVC, GCC, dan Clang. Fitur termasuk:
Pengguna dapat membuat profil platform penargetan perangkat lunak apa pun dengan kompiler GCC atau Clang. MTuner hadir dengan dukungan bawaan untuk platform Windows, PlayStation 4 dan PlayStation 3.
sumber
Pada Windows Anda dapat menggunakan tumpukan debug CRT .
Ya, jangan gunakan manajemen memori manual (jika Anda pernah menelepon
delete
ataudelete[]
secara manual, maka Anda salah melakukannya). Gunakan RAII dan smart pointer, batasi alokasi heap hingga minimum absolut (sebagian besar waktu, variabel otomatis sudah cukup).sumber
Menjawab bagian kedua dari pertanyaan Anda,
Ya ada. Dan ini adalah salah satu perbedaan utama antara C dan C ++.
Dalam C ++, Anda tidak boleh menelepon
new
ataudelete
dalam kode pengguna Anda. RAII adalah teknik yang sangat umum digunakan, yang cukup banyak memecahkan masalah manajemen sumber daya. Setiap sumber daya dalam program Anda (sumber daya adalah apa saja yang harus diperoleh, dan kemudian, dirilis: pegangan file, soket jaringan, koneksi basis data, tetapi juga alokasi memori biasa, dan dalam beberapa kasus, pasangan panggilan API (BeginX ( ) / EndX (), LockY (), UnlockY ()), harus dibungkus dalam kelas, di mana:new
jika sumber daya itu adalah alokasi memroy)Kelas ini kemudian dipakai secara lokal, di stack, atau sebagai anggota kelas, dan bukan dengan memanggil
new
dan menyimpan pointer.Anda sering tidak perlu mendefinisikan sendiri kelas-kelas ini. Wadah pustaka standar berperilaku dengan cara ini juga, sehingga setiap objek yang disimpan ke dalam
std::vector
akan dibebaskan ketika vektor dihancurkan. Jadi sekali lagi, jangan menyimpan pointer ke dalam wadah (yang mengharuskan Anda meneleponnew
dandelete
), tetapi objek itu sendiri (yang memberi Anda manajemen memori gratis ). Demikian juga, kelas penunjuk pintar dapat digunakan untuk dengan mudah membungkus objek yang hanya harus dialokasikan dengannew
, dan mengontrol masa hidup mereka.Ini berarti bahwa ketika objek keluar dari ruang lingkup, ia secara otomatis dihancurkan, dan sumber dayanya dilepaskan dan dibersihkan.
Jika Anda melakukan ini secara konsisten di seluruh kode Anda, Anda tidak akan memiliki kebocoran memori. Segala sesuatu yang bisa bocor terkait dengan destruktor yang dijamin akan dipanggil ketika kontrol meninggalkan ruang lingkup di mana objek tersebut dinyatakan.
sumber
AddressSanitizer (ASan) adalah pendeteksi kesalahan memori yang cepat. Ia menemukan bug yang digunakan-setelah-bebas dan {heap, stack, global} -buffer dalam program C / C ++. Ia menemukan:
Alat ini sangat cepat. Perlambatan rata-rata dari program instrument adalah ~ 2x.
sumber
Selain alat dan metode yang disediakan dalam jawaban lain, alat analisis kode statis dapat digunakan untuk mendeteksi kebocoran memori (dan masalah lainnya juga). Alat gratis yang tangguh adalah Cppcheck. Tetapi ada banyak alat lain yang tersedia. Wikipedia memiliki daftar alat analisis kode statis.
sumber
Pastikan bahwa semua memori tumpukan berhasil dibebaskan. Tidak perlu jika Anda tidak pernah mengalokasikan memori pada heap. Jika ya, hitung berapa kali Anda menyimpan memori, dan hitung berapa kali Anda membebaskan memori.
sumber
"Baru" atau "hapus" tidak boleh digunakan dalam kode aplikasi. Sebaliknya, buat tipe baru yang menggunakan idiom manajer / pekerja, di mana kelas manajer mengalokasikan dan membebaskan memori dan meneruskan semua operasi lainnya ke objek pekerja.
Sayangnya ini lebih banyak pekerjaan daripada seharusnya karena C ++ tidak memiliki "operator" yang berlebihan. Ini bahkan lebih banyak bekerja di hadapan polimorfisme.
Tapi ini sepadan dengan usaha karena Anda tidak perlu khawatir tentang kebocoran memori, yang berarti Anda bahkan tidak perlu mencarinya.
sumber