Membuang objek dengan benar pada server termination

9

Saya sedang mengerjakan proyek C ++ besar. Ini terdiri dari server yang memaparkan REST API, menyediakan antarmuka yang sederhana dan ramah pengguna untuk sistem yang sangat luas yang terdiri dari banyak server lain. Basis kode cukup besar dan kompleks, dan berkembang melalui waktu tanpa desain awal yang tepat. Tugas saya adalah mengimplementasikan fitur-fitur baru dan memperbaiki / memperbaiki kode lama agar lebih stabil dan dapat diandalkan.

Saat ini, server membuat sejumlah objek berumur panjang yang tidak pernah dihentikan atau dibuang ketika proses berakhir. Ini membuat Valgrind hampir tidak dapat digunakan untuk deteksi kebocoran, karena tidak mungkin untuk membedakan antara ribuan (yang diragukan) kebocoran yang sah dari yang "berbahaya".

Ide saya adalah untuk memastikan bahwa semua objek dibuang sebelum pemutusan, tetapi ketika saya membuat proposal ini, kolega saya dan bos saya menentang saya menunjukkan bahwa OS akan membebaskan memori itu (yang jelas bagi semua orang) dan membuang benda-benda akan memperlambat shutdown server (yang, pada saat ini, pada dasarnya adalah panggilan ke std::exit). Saya menjawab bahwa memiliki prosedur mematikan "bersih" tidak selalu berarti bahwa seseorang harus menggunakannya. Kita selalu bisa menelepon std::quick_exitatau hanya kill -9proses jika kita merasa tidak sabar.

Mereka menjawab "kebanyakan daemon dan proses Linux tidak perlu repot membebaskan memori pada saat shutdown". Walaupun saya dapat melihat itu, juga benar bahwa proyek kami memang membutuhkan debugging memori yang akurat, karena saya sudah menemukan korupsi memori, membebaskan dua kali lipat dan variabel yang tidak diinisialisasi.

Apa yang kamu pikirkan? Apakah saya melakukan upaya sia-sia? Jika tidak, bagaimana saya bisa meyakinkan kolega dan bos saya? Jika ya, mengapa, dan apa yang harus saya lakukan?

Marty
sumber
Selain argumen kinerja (yang masuk akal!), Apakah banyak upaya untuk mengisolasi objek yang berumur panjang dan menambahkan kode pembersihan untuknya?
Doc Brown

Jawaban:

7

Tambahkan sakelar ke proses server yang dapat digunakan selama pengukuran valgrind yang akan melepaskan semua memori. Anda dapat menggunakan sakelar ini untuk pengujian. Dampaknya akan minimal selama operasi normal.

Kami memiliki proses yang berjalan lama yang akan memakan waktu beberapa menit untuk melepaskan 1000 objek. Jauh lebih efisien untuk keluar begitu saja dan membiarkan mereka mati. Sayangnya, seperti yang Anda sebutkan, ini membuatnya sulit untuk mendeteksi kebocoran memori sebenarnya dengan valgrind atau alat lain.

Ini adalah kompromi yang baik untuk pengujian kami tanpa memengaruhi kinerja normal.

Bill Door
sumber
1
+1 Pragmatisme FTW. Ada nilai dalam pengukuran, tetapi ada juga nilai dalam shutdown cepat.
Ross Patterson
2
Sebagai alternatif untuk beralih baris perintah, Anda mungkin juga ingin mempertimbangkan untuk mengimplementasikan penghapusan objek permanen di dalam blok #ifdef DEBUG.
Jules
3

Kuncinya di sini adalah ini:

Walaupun saya bisa melihat itu, juga benar bahwa proyek kami memang membutuhkan debugging memori yang akurat, karena saya sudah menemukan korupsi memori, membebaskan dua kali lipat dan variabel yang tidak diinisialisasi.

Ini cukup banyak secara langsung menyiratkan bahwa basis kode Anda dirakit dari tidak lebih dari harapan dan string. Pemrogram C ++ yang kompeten tidak memiliki frees ganda.

Anda benar-benar mengejar upaya sia-sia - seperti pada, Anda mengatasi satu gejala kecil dari masalah aktual, yaitu bahwa kode Anda hampir dapat diandalkan seperti modul layanan Apollo 13.

Jika Anda memprogram server Anda dengan benar dengan RAII, masalah ini tidak akan terjadi, dan masalah dalam pertanyaan Anda akan dihilangkan. Plus, kode Anda mungkin benar-benar dieksekusi dengan benar dari waktu ke waktu. Jadi, itu jelas pilihan terbaik.

DeadMG
sumber
Tentu saja masalahnya terletak pada gambaran yang lebih besar. Akan tetapi, sangat jarang seseorang dapat menemukan sumber daya dan izin untuk memperbaiki / menulis ulang proyek agar lebih baik.
Cengiz Can
@Engizcan: Jika Anda ingin memperbaiki bug, Anda perlu melakukan refactor. Begitulah cara kerjanya.
DeadMG
2

Salah satu pendekatan yang baik adalah mempersempit diskusi dengan kolega Anda dengan cara klasifikasi. Mengingat basis kode yang besar, tentu saja tidak ada satu alasan tunggal tetapi lebih dari satu, alasan (dapat diidentifikasi) untuk objek yang berumur panjang.

Contoh:

  • Benda berumur panjang yang tidak dirujuk oleh siapa pun (kebocoran nyata). Ini adalah kesalahan logika pemrograman. Perbaiki yang dengan prioritas rendah KECUALI mereka bertanggung jawab atas jejak memori Anda untuk tumbuh dari waktu ke waktu (dan menurunkan kualitas aplikasi Anda). Jika mereka membuat jejak memori Anda tumbuh seiring waktu, perbaiki dengan prioritas yang lebih tinggi.

  • Benda hidup panjang, yang masih dirujuk tetapi tidak digunakan lagi (karena logika program), tetapi yang tidak membuat jejak memori Anda tumbuh. Tinjau kode dan coba temukan bug lain yang mengarah ke sana. Tambahkan komentar ke basis kode jika itu adalah optimasi (kinerja) yang disengaja.

  • Benda hidup panjang "dengan desain". Pola singleton misalnya. Mereka memang sulit untuk dihilangkan, terutama jika itu adalah aplikasi multi-utas.

  • Objek daur ulang. Benda berumur panjang tidak selalu buruk. Mereka juga bisa bermanfaat. Alih-alih memiliki alokasi / deallokasi memori frekuensi tinggi, menambahkan objek yang saat ini tidak digunakan ke dalam wadah untuk menarik ketika blok memori seperti itu diperlukan lagi dapat membantu mempercepat aplikasi dan menghindari tumpukan fragmentasi. Mereka harus mudah dibebaskan pada waktu shutdown, mungkin dalam build "instrumentasi / dicentang" khusus.

  • "shared objects" - objek yang digunakan (direferensikan) oleh beberapa objek lain dan tidak ada yang tahu persis kapan disimpan untuk membebaskannya. Pertimbangkan untuk mengubahnya menjadi objek terhitung referensi.

Setelah Anda mengklasifikasikan alasan sebenarnya untuk objek-objek yang tidak direferensikan, jauh lebih mudah untuk memasukkan diskusi kasus per kasus dan menemukan resolusi.

BitTickler
sumber
0

IMHO, daya tahan benda-benda ini tidak boleh hanya dibuat dan dibiarkan mati ketika sistem dimatikan. Ini berbau variabel global, yang kita semua tahu adalah buruk buruk buruk buruk. Terutama di zaman smart pointer, tidak ada alasan untuk melakukan ini selain kemalasan. Tetapi yang lebih penting, ini menambah tingkat hutang teknis ke sistem Anda yang mungkin harus dihadapi seseorang suatu hari nanti.

Gagasan "utang teknis" adalah ketika Anda mengambil jalan pintas seperti ini, ketika seseorang ingin mengubah kode di masa depan (katakanlah, saya ingin dapat membuat klien masuk ke "mode offline" atau "mode tidur" ", atau saya ingin dapat mengganti server tanpa memulai kembali prosesnya) mereka harus berusaha untuk melakukan apa yang Anda lewatkan lakukan. Tetapi mereka akan menjaga kode Anda, sehingga mereka tidak akan tahu sebanyak itu tentang Anda, sehingga akan memakan waktu lebih lama (Saya tidak berbicara 20% lebih lama, saya berbicara 20x lebih lama!). Bahkan jika itu Anda, maka Anda tidak akan bekerja pada kode khusus ini selama berminggu-minggu atau berbulan-bulan, dan itu akan memakan waktu lebih lama untuk membersihkan sarang laba-laba agar dapat menerapkannya dengan benar.

Dalam hal ini, tampaknya Anda memiliki hubungan yang sangat erat antara objek server dan objek "berumur panjang" ... ada kalanya catatan dapat (dan harus) hidup lebih lama dari koneksi ke server. Mempertahankan setiap perubahan tunggal pada suatu objek di server bisa menjadi sangat mahal, jadi biasanya lebih baik objek yang benar-benar ditelusuri menangani ke objek server, dengan menyimpan dan memperbarui panggilan yang benar-benar mengubah server. Ini biasa disebut pola rekaman aktif. Lihat:

http://en.wikipedia.org/wiki/Active_record_pattern

Dalam C ++, saya akan meminta setiap record aktif memiliki lemah_ptr ke server, yang bisa melempar sesuatu dengan cerdas jika koneksi server menjadi gelap. Kelas-kelas ini dapat berupa populasi malas atau batch, tergantung pada kebutuhan Anda, tetapi masa pakai objek-objek tersebut hanya di tempat mereka digunakan.

Lihat juga:

Apakah membuang-buang waktu untuk membebaskan sumber daya sebelum saya keluar dari suatu proses?

Yang lain

IdeHat
sumber
This reeks of global variablesBagaimana Anda beralih dari "ada ribuan objek yang perlu dibebaskan" menjadi "mereka harus bersifat global"? Itu adalah lompatan logika.
Doval
0

Jika Anda dapat dengan mudah mengidentifikasi di mana objek yang harus bertahan hidup dialokasikan tanpa batas waktu, sekali kemungkinan akan mengalokasikannya menggunakan mekanisme alokasi alternatif sehingga mereka tidak muncul dalam laporan kebocoran valgrind atau hanya tampak sebagai alokasi tunggal.

Jika Anda tidak terbiasa dengan ide tersebut, inilah artikel tentang cara impoten alokasi memori khusus di c ++ , meskipun perhatikan bahwa solusi Anda bisa lebih sederhana daripada contoh dalam artikel itu karena Anda tidak perlu menangani penghapusan sama sekali !

Jules
sumber