Saat Anda keluar dari aplikasi C, apakah memori malloc-ed secara otomatis dibebaskan?

93

Katakanlah saya memiliki kode C berikut:

int main () {
  int *p = malloc(10 * sizeof *p);
  *p = 42;
  return 0;  //Exiting without freeing the allocated memory
}

Ketika saya mengkompilasi dan menjalankan program C itu, yaitu setelah mengalokasikan beberapa ruang dalam memori, apakah memori yang saya alokasikan akan tetap dialokasikan (yaitu pada dasarnya mengambil ruang) setelah saya keluar dari aplikasi dan prosesnya berakhir?

Andreas Grech
sumber
9
ini adalah "gaya yang baik" untuk membersihkan memori Anda, bukan karena Anda mungkin menjalankan OS yang tidak memiliki memori terlindungi (yang merupakan saran utama di bawah), tetapi karena ini meningkatkan kemungkinan Anda akan menemukan kebocoran memori, dan terus kode Anda ramping dan benar ...
Matt Joiner

Jawaban:

113

Itu tergantung pada sistem operasi. Mayoritas sistem operasi modern (dan semua sistem operasi utama) akan membebaskan memori yang tidak dibebaskan oleh program saat program berakhir.

Mengandalkan ini adalah praktik yang buruk dan lebih baik membebaskannya secara eksplisit. Masalahnya bukan hanya kode Anda terlihat buruk. Anda mungkin memutuskan ingin mengintegrasikan program kecil Anda ke program yang lebih besar dan berjalan lama. Kemudian beberapa saat kemudian Anda harus menghabiskan waktu berjam-jam melacak kebocoran memori.
Mengandalkan fitur sistem operasi juga membuat kode kurang portabel.

Yacoby
sumber
16
Saya pernah menemukan win98 pada platform tertanam, dan berdasarkan pengalaman itu, saya dapat mengatakan bahwa itu TIDAK membebaskan memori saat program ditutup.
San Jacinto
8
@Ken Itu adalah contoh. Juga, ada garis antara YAGNI dan pengkodean yang ceroboh. Tidak membebaskan sumber daya melewatinya. Prinsip YAGNI juga dimaksudkan untuk diterapkan pada fitur, bukan kode yang membuat program bekerja dengan benar. (Dan tidak membebaskan memori adalah bug).
Yacoby
5
+1: hal yang paling penting untuk dipertimbangkan adalah bahwa manajemen memori adalah seperti yang dikatakan Yacoby dengan tepat: "fitur dari sistem operasi" . Kecuali saya salah, bahasa pemrograman tidak menentukan apa yang terjadi sebelum atau sesudah eksekusi program.
D. Shawley
9
Membebaskan memori secara manual membutuhkan lebih banyak waktu, membutuhkan lebih banyak kode, dan menimbulkan kemungkinan bug (beri tahu saya bahwa Anda belum pernah melihat bug dalam kode deallocation!). Tidaklah "ceroboh" untuk dengan sengaja menghilangkan sesuatu yang lebih buruk dalam segala hal untuk kasus penggunaan Anda. Kecuali atau sampai Anda bermaksud menjalankannya pada beberapa sistem kuno / kecil yang tidak dapat membebaskan halaman setelah penghentian proses, atau mengintegrasikannya ke dalam program yang lebih besar (YAGNI), ini tampak seperti kerugian bersih bagi saya. Saya tahu itu menyakitkan ego programmer untuk berpikir untuk tidak membersihkannya sendiri, tapi dalam cara praktis apa itu sebenarnya lebih baik?
Ken
6
Siapa pun yang mengusulkan kebocoran memori pada SO harus dicabut dari semua reputasi dan lencana
Tersembunyi
53

Secara umum, sistem operasi serba guna modern melakukan pembersihan setelah proses dihentikan . Hal ini diperlukan karena alternatifnya adalah sistem kehilangan sumber daya dari waktu ke waktu dan memerlukan boot ulang karena program yang ditulis dengan buruk atau hanya memiliki bug yang jarang terjadi yang membocorkan sumber daya.

Membuat program Anda secara eksplisit membebaskan sumber dayanya bisa menjadi praktik yang baik karena berbagai alasan, seperti:

  • Jika Anda memiliki sumber daya tambahan yang tidak dibersihkan oleh OS saat keluar, seperti file sementara atau segala jenis perubahan pada status sumber daya eksternal, maka Anda memerlukan kode untuk menangani semua hal tersebut saat keluar, dan ini sering kali dikombinasikan secara elegan dengan membebaskan memori.
  • Jika program Anda mulai memiliki masa hidup yang lebih lama, maka Anda tidak ingin satu - satunya cara untuk membebaskan memori adalah dengan keluar. Misalnya, Anda mungkin ingin mengubah program Anda menjadi server (daemon) yang terus berjalan sambil menangani banyak permintaan untuk unit kerja individual, atau program Anda mungkin menjadi bagian kecil dari program yang lebih besar.

Namun, berikut ini alasan untuk melewati ruang kosong: pematian yang efisien . Misalnya, aplikasi Anda berisi cache yang besar di memori. Jika saat keluar, ia melewati seluruh struktur cache dan membebaskannya satu per satu, itu tidak memiliki tujuan yang berguna dan membuang sumber daya. Terutama, pertimbangkan kasus di mana halaman memori yang berisi cache Anda telah ditukar ke disk oleh sistem operasi; dengan menjalankan struktur dan membebaskannya, Anda membawa semua halaman itu kembali ke memori sekaligus , membuang-buang waktu dan energi yang signifikan tanpa manfaat yang sebenarnya, dan bahkan mungkin menyebabkan program lain di sistem ditukar!

Sebagai contoh terkait, ada server berkinerja tinggi yang bekerja dengan membuat proses untuk setiap permintaan, lalu keluar setelah selesai; dengan ini berarti mereka bahkan tidak perlu melacak alokasi memori , dan tidak pernah melakukan pembebasan atau pengumpulan sampah sama sekali, karena semuanya akan hilang begitu saja kembali ke memori bebas sistem operasi pada akhir proses. (Hal yang sama dapat dilakukan dalam proses menggunakan pengalokasi memori khusus, tetapi membutuhkan pemrograman yang sangat hati-hati; pada dasarnya membuat gagasan sendiri tentang "proses ringan" dalam proses OS.)

Kevin Reid
sumber
11

Saya minta maaf untuk memposting begitu lama setelah posting terakhir ke utas ini.

Satu poin tambahan. Tidak semua program berhasil keluar dengan baik. Crash dan ctrl-C, dll. Akan menyebabkan program keluar dengan cara yang tidak terkontrol. Jika OS Anda tidak membebaskan heap Anda, membersihkan tumpukan Anda, menghapus variabel statis, dll, Anda pada akhirnya akan merusak sistem Anda karena kebocoran memori atau lebih buruk.

Selain menarik untuk ini, crash / break di Ubuntu, dan saya menduga semua OS modern lainnya, memang memiliki masalah dengan sumber daya yang "ditangani. Soket, file, perangkat, dll. Dapat tetap" terbuka "ketika program berakhir / crash. Ini juga praktik yang baik untuk menutup apa pun dengan "pegangan" atau "deskriptor" sebagai bagian dari pembersihan sebelum keluar dengan anggun.

Saya sedang mengembangkan program yang sangat banyak menggunakan soket. Ketika saya terjebak dalam hang, saya harus menekan ctrl-c untuk melepaskannya, sehingga membuat soket saya lepas. Saya menambahkan std :: vector untuk mengumpulkan daftar semua soket yang terbuka dan penangan sigaction yang menangkap sigint dan sigterm. Pawang menjalankan daftarnya dan menutup soketnya. Saya berencana membuat rutinitas pembersihan serupa untuk digunakan sebelum lemparan yang akan menyebabkan penghentian dini.

Ada yang mau mengomentari desain ini?

Wes Miller
sumber
1
Saya senang Anda mengatakan ini, karena saya memiliki program yang meninggalkan sumber daya soket, dan sistem Ubuntu kami memerlukan boot ulang setiap dua minggu atau memori mulai habis, dan ada banyak memori. Saya tidak yakin sumber daya sistem dirobohkan jika Anda lupa untuk membersihkannya.
octopusgrabbus
8
Stackoverflow bukanlah forum; tidak ada yang salah dengan menjawab pertanyaan lama. meta.stackexchange.com/questions/20524/reviving-old-questions
mk12
6

Apa yang terjadi di sini ( dalam OS modern ), adalah bahwa program Anda berjalan di dalam "proses" -nya sendiri. Ini adalah entitas sistem operasi yang diberkahi dengan ruang alamatnya sendiri, deskriptor file, dll. mallocPanggilan Anda mengalokasikan memori dari "heap", atau halaman memori yang tidak terisi yang ditetapkan untuk proses Anda.

Ketika program Anda berakhir, seperti dalam contoh ini, semua sumber daya yang ditugaskan untuk proses Anda hanya didaur ulang / dihancurkan oleh sistem operasi. Dalam kasus memori, semua halaman memori yang ditetapkan untuk Anda hanya ditandai sebagai "bebas" dan didaur ulang untuk digunakan proses lain. Halaman adalah konsep tingkat yang lebih rendah daripada yang ditangani malloc-- sebagai hasilnya, spesifikasi malloc / free semuanya hanyut begitu semuanya dibersihkan.

Ini setara dengan moral, ketika Anda selesai menggunakan laptop dan ingin memberikannya kepada teman, Anda tidak perlu repot-repot menghapus setiap file satu per satu. Anda tinggal memformat hard drive.

Semua ini mengatakan, seperti yang dicatat oleh semua penjawab lainnya, mengandalkan ini bukanlah praktik yang baik:

  1. Anda harus selalu memprogram untuk menjaga sumber daya, dan dalam C itu berarti memori juga. Anda mungkin akhirnya menyematkan kode Anda di perpustakaan, atau mungkin berakhir lebih lama dari yang Anda harapkan.
  2. Beberapa OS (yang lebih lama dan mungkin beberapa yang tertanam modern) mungkin tidak mempertahankan batas proses yang sulit, dan alokasi Anda mungkin memengaruhi ruang alamat orang lain.
Ben Zotto
sumber
4

Iya. OS membersihkan sumber daya. Nah ... NetWare versi lama tidak.

Sunting: Seperti yang ditunjukkan San Jacinto, pasti ada sistem (selain dari NetWare) yang tidak melakukan itu. Bahkan dalam program sekali pakai, saya mencoba membiasakan diri untuk membebaskan semua sumber daya hanya untuk mempertahankan kebiasaan itu.

Mark Wilkins
sumber
3
Saya tidak downvoting, tapi ini adalah posting yang cukup berbahaya untuk anak cucu. DOS masih digunakan pada banyak platform tertanam, dan saya SANGAT meragukan bahwa itu melakukan pembersihan memori untuk Anda. Generalisasi yang luas itu salah.
San Jacinto
@ San Jacinto: Itu poin yang bagus. Itulah mengapa saya membuat referensi NetWare, tetapi mungkin bisa menggunakan klarifikasi. Saya akan mengeditnya sedikit.
Mark Wilkins
3
@San DOS bukan OS multi-tasking - ketika program DOS (tidak termasuk TSR) berakhir, semua memori tersedia untuk program berikutnya yang akan dimuat.
@Neil terima kasih atas pengingatnya, tapi saya mengacu pada program seperti TSR yang akan diluncurkan ketika suatu peristiwa terjadi, seperti penggunaan umum untuk sistem tertanam. Meskipun demikian, terima kasih atas keahlian dan klarifikasi Anda di mana saya gagal :)
San Jacinto
2

Ya, sistem operasi melepaskan semua memori saat proses berakhir.

Draemon
sumber
Saya tidak mengerti mengapa ini tidak disukai. memori malloc'ed akan dilepaskan ketika proses mati (definisi wikipedia dari malloc mengatakan demikian)
Arve
7
Wikipedia bukanlah manual untuk setiap OS yang ada. Kebanyakan OS modern akan mendapatkan kembali memori, tetapi tidak semua (dan terutama tidak semua yang lama) melakukannya. Tambahkan ke itu, mallochanya bisa menjanjikan apa yang akan dilakukan C dengan memori; menurut desain, C tidak menjamin banyak hal tentang perilaku di luar C itu sendiri. Jika aplikasi mati secara tidak terduga, janji apa pun yang dibuat library waktu proses menjadi batal demi hukum, karena tidak lagi berlaku untuk memenuhi janji tersebut.
cHao
2

Itu tergantung, sistem operasi biasanya akan membersihkannya untuk Anda, tetapi jika Anda mengerjakan misalnya perangkat lunak yang disematkan maka itu mungkin tidak dirilis.

Pastikan Anda membebaskannya, ini dapat menghemat banyak waktu nanti ketika Anda mungkin ingin mengintegrasikannya ke dalam proyek besar.

Charles
sumber
0

Itu sangat tergantung pada sistem operasi, tetapi untuk semua sistem operasi yang pernah Anda temui, alokasi memori akan hilang saat proses keluar.


sumber
0

Saya pikir pembebasan langsung adalah yang terbaik. Perilaku tidak terdefinisi adalah hal terburuk, jadi jika Anda memiliki akses sementara itu masih ditentukan dalam proses Anda, lakukanlah, ada banyak alasan bagus yang diberikan orang untuk itu.

Mengenai di mana, atau apakah, saya menemukan bahwa di W98, pertanyaan sebenarnya adalah 'kapan' (saya tidak melihat postingan yang menekankan hal ini). Program template kecil (untuk input MIDI SysEx, menggunakan berbagai ruang malloc'd) akan membebaskan memori di bit WM_DESTROY dari WndProc, tetapi ketika saya memindahkannya ke program yang lebih besar, program tersebut macet saat keluar. Saya berasumsi ini berarti saya mencoba membebaskan apa yang telah dibebaskan OS selama pembersihan yang lebih besar. Jika saya melakukannya di WM_CLOSE, lalu memanggil DestroyWindow (), semuanya bekerja dengan baik, keluar bersih instan.

Meskipun ini tidak persis sama dengan buffer MIDI, ada kesamaan yaitu yang terbaik adalah menjaga proses tetap utuh, bersihkan sepenuhnya, lalu keluar. Dengan potongan memori sederhana ini sangat cepat. Saya menemukan bahwa banyak buffer kecil bekerja lebih cepat dalam pengoperasian dan pembersihan dibandingkan buffer besar yang lebih sedikit.

Pengecualian mungkin ada, seperti yang dikatakan seseorang ketika menghindari menarik potongan memori besar kembali dari file swap pada disk, tetapi bahkan itu dapat diminimalkan dengan menyimpan lebih banyak, dan lebih kecil, ruang yang dialokasikan.


sumber