Mengapa bahasa seperti C dan C ++ tidak memiliki pengumpulan sampah, sementara Java memilikinya? [Tutup]


57

Yah, saya tahu bahwa ada hal-hal seperti malloc / gratis untuk C, dan baru / menggunakan-a-destruktor untuk manajemen memori dalam C ++, tapi saya bertanya-tanya mengapa tidak ada "pembaruan baru" untuk bahasa-bahasa ini yang memungkinkan pengguna untuk punya opsi untuk mengelola memori secara manual, atau agar sistem melakukannya secara otomatis (pengumpulan sampah)?

Agak dari pertanyaan newb-ish, tetapi hanya berada di CS selama sekitar satu tahun.


9
Kami punya modul dalam pengembangan iPhone semester ini. Setelah mengkode aplikasi untuk Android selama 2 tahun, pertanyaan ini mengejutkan sebagian besar kelas. Baru sekarang kita melihat berapa jam sebenarnya Java menyelamatkan kita karena tidak perlu melacak kesalahan manajemen memori yang buruk dan tidak harus menulis kode pelat ketel.
siamii

7
@NullUserException, karena tidak menentukan cara untuk mendapatkan kembali memori yang cukup banyak menyiratkan GC.
Winston Ewert

1
@ bizso09: Apakah Anda sudah melihat ARC? Tidak perlu GC lambat / gemuk / non-deterministik ketika Anda mendapat dukungan sistem untuk penghitungan referensi: developer.apple.com/technologies/ios5
JBRWilkinson

3
Jawaban atas pertanyaan yang cukup bagus ini penuh dengan omong kosong agama.
abatishchev

1
Dalam C dan C ++ dimungkinkan untuk mengambil pointer, melemparkannya ke int dan menambahkan nomor ke dalamnya. Kemudian kurangi angka dari int dan masukkan hasilnya kembali ke sebuah pointer. Anda akan mendapatkan pointer yang sama seperti sebelumnya. Selamat mencoba menerapkan GC yang TIDAK mengumpulkan memori itu sementara alamatnya disimpan hanya dalam variabel yang juga memiliki nilai lain. Saya tahu contohnya konyol tetapi daftar tertaut XOR menggunakan sesuatu yang serupa. Saya akan memposting ini sebagai jawaban tetapi pertanyaannya sudah ditutup.
Marian Spanik

Jawaban:


71

Pengumpulan sampah membutuhkan struktur data untuk melacak alokasi dan / atau penghitungan referensi. Ini menciptakan overhead dalam memori, kinerja, dan kompleksitas bahasa. C ++ dirancang untuk menjadi "dekat dengan logam", dengan kata lain, dibutuhkan sisi kinerja yang lebih tinggi dari fitur pengorbanan vs kenyamanan. Bahasa lain membuat pengorbanan itu berbeda. Ini adalah salah satu pertimbangan dalam memilih bahasa, yang mana Anda lebih suka.

Yang mengatakan, ada banyak skema untuk penghitungan referensi dalam C ++ yang cukup ringan dan berkinerja, tetapi mereka berada di perpustakaan, baik komersial dan sumber terbuka, bukan bagian dari bahasa itu sendiri. Penghitungan referensi untuk mengelola objek seumur hidup tidak sama dengan pengumpulan sampah, tetapi menangani banyak jenis masalah yang sama, dan lebih cocok dengan pendekatan dasar C ++.


26
Masalah kedua adalah GC bersifat non-deterministik. Objek mungkin atau mungkin masih tidak ada dalam memori lama setelah program "menjatuhkannya". Siklus hidup Refcount adalah deterministik, ketika referensi terakhir dijatuhkan, memori dijatuhkan. Ini memiliki implikasi tidak hanya untuk efisiensi memori, tetapi juga untuk debugging. Kesalahan pemrograman yang umum adalah objek "zombie", memori referensi yang secara teoritis telah dijatuhkan. GC jauh lebih mungkin untuk menutupi efek ini, dan menghasilkan bug yang intermiten dan sangat sulit dilacak.
kylben

22
- gc modern tidak melacak alokasi atau menghitung referensi. Mereka membuat grafik dari semua yang saat ini ada di stack dan hanya mengembun dan menghapus yang lainnya (disederhanakan), dan GC biasanya menghasilkan kompleksitas bahasa yang berkurang . Bahkan manfaat kinerja dipertanyakan.
Joel Coehoorn

13
Eh, @kylben, inti dari memiliki GC otomatis dimasukkan ke dalam bahasa adalah bahwa menjadi tidak mungkin untuk referensi objek zombie, karena GC hanya membebaskan objek yang tidak mungkin untuk referensi! Anda mendapatkan jenis bug yang sulit dilacak ketika Anda melakukan kesalahan dengan manajemen memori manual.
Ben

14
-1, GC tidak menghitung referensi. Plus, tergantung pada penggunaan memori Anda dan skema alokasi, GC bisa lebih cepat (dengan overhead dalam penggunaan memori). Jadi argumen tentang kinerja juga salah. Hanya yang dekat dengan logam adalah titik yang valid sebenarnya.
deadalnix

14
Baik perhitungan penghitungan referensi Java maupun C #: Skema GC yang didasarkan pada penghitungan referensi cukup primitif dalam perbandingan dan berkinerja jauh lebih buruk daripada pengumpul sampah modern (terutama karena mereka perlu melakukan penulisan memori untuk mengubah jumlah referensi setiap kali Anda menyalin referensi!)
mikera

44

Sebenarnya, tidak ada manajemen memori sama sekali dalam bahasa C. malloc () dan free () bukan kata kunci dalam bahasa tersebut, tetapi hanya fungsi yang dipanggil dari perpustakaan. Perbedaan ini mungkin terlalu rumit sekarang, karena malloc () dan free () adalah bagian dari pustaka standar C, dan akan disediakan oleh implementasi standar C yang sesuai, tetapi ini tidak selalu benar di masa lalu.

Mengapa Anda ingin bahasa tanpa standar untuk manajemen memori? Ini kembali ke asal C sebagai 'perakitan portabel'. Ada banyak kasus perangkat keras dan algoritma yang dapat mengambil manfaat dari, atau bahkan memerlukan, teknik manajemen memori khusus. Sejauh yang saya tahu, tidak ada cara untuk sepenuhnya menonaktifkan manajemen memori asli Java dan menggantinya dengan Anda sendiri. Ini sama sekali tidak dapat diterima dalam beberapa situasi sumber daya kinerja tinggi / minimal. C memberikan fleksibilitas yang hampir lengkap untuk memilih dengan tepat infrastruktur apa yang akan digunakan oleh program Anda. Harga yang dibayarkan adalah bahwa bahasa C memberikan sedikit bantuan dalam penulisan kode bebas bug yang benar.


2
+1 satu untuk jawaban keseluruhan yang baik, tetapi juga terutama untuk "Harga yang dibayar adalah bahwa bahasa C memberikan sedikit bantuan dalam penulisan kode bebas bug yang benar"
Shivan Dragon

2
C memang memiliki manajemen memori - tetapi hanya berfungsi, sehingga orang hampir tidak menyadarinya. Ada memori statis, register dan tumpukan. Sampai Anda mulai mengalokasikan dari tumpukan, Anda baik-baik saja dan keren. Alokasi tumpukan yang mengacaukan segalanya. Adapun Java, semua orang dapat menulis runtime Java mereka sendiri - ada banyak untuk dipilih, termasuk apa yang bisa disebut "System's Java". .NET dapat melakukan hampir semua yang dapat dilakukan C - hanya tertinggal di belakang kemampuan asli C ++ (mis. Kelas hanya dikelola dalam .NET). Tentu saja, Anda juga memiliki C ++. NET, yang memiliki semua yang dilakukan C ++, dan segalanya. NET.
Luaan

1
@Luaan Saya akan mengatakan itu definisi yang sangat murah hati untuk memiliki "manajemen memori" "Sampai Anda mulai mengalokasikan dari tumpukan, Anda baik-baik saja dan keren. Alokasi tumpukan yang mengacaukan segalanya", Itu seperti mengatakan sebuah mobil adalah sebuah pesawat yang sangat bagus, itu tidak bisa terbang.
Charles E. Grant

1
@ CharlesE.Grant Nah, bahasa murni fungsional dapat melakukan segalanya dengan manajemen memori semacam itu. Hanya karena alokasi tumpukan merupakan trade off yang baik dalam beberapa kasus penggunaan tidak berarti bahwa itu adalah tolok ukur untuk semua bahasa / runtime. Ini tidak seperti manajemen memori berhenti menjadi "manajemen memori" hanya karena itu sederhana, lurus ke depan, tersembunyi di balik layar. Merancang alokasi memori statis masih merupakan manajemen memori, seperti penggunaan stack yang baik dan apa pun yang Anda miliki.
Luaan

"implementasi standar apa pun yang sesuai" tidak benar, hanya untuk penerapan lingkungan host yang sesuai standar. Beberapa Platform / Perpustakaan Standar, sebagian besar untuk Mikrokontroler tertanam 8 atau 16-Bit, tidak menyediakan malloc()atau free(). (contohnya adalah MLAP-Compiler untuk PIC)
12431234123412341234123

32

Jawaban sebenarnya adalah bahwa satu-satunya cara untuk membuat mekanisme pengumpulan sampah yang aman dan efisien adalah dengan memiliki dukungan tingkat bahasa untuk referensi yang tidak jelas. (Atau, sebaliknya, kurangnya dukungan tingkat bahasa untuk manipulasi memori langsung.)

Java dan C # dapat melakukannya karena mereka memiliki tipe referensi khusus yang tidak dapat dimanipulasi. Ini memberikan runtime kebebasan untuk melakukan hal-hal seperti memindahkan objek yang dialokasikan dalam memori , yang sangat penting untuk implementasi GC berkinerja tinggi.

Sebagai catatan, tidak ada implementasi GC modern yang menggunakan penghitungan referensi , sehingga benar-benar ikan haring merah. GC modern menggunakan koleksi generasi, di mana alokasi baru diperlakukan pada dasarnya dengan cara yang sama seperti tumpukan alokasi dalam bahasa seperti C ++, dan kemudian secara berkala setiap objek yang baru dialokasikan yang masih hidup dipindahkan ke ruang "selamat" yang terpisah, dan seluruh generasi benda dialokasikan sekaligus.

Pendekatan ini memiliki pro dan kontra: terbalik adalah bahwa tumpukan alokasi dalam bahasa yang mendukung GC secepat alokasi tumpukan dalam bahasa yang tidak mendukung GC, dan downside adalah bahwa objek yang perlu melakukan pembersihan sebelum dihancurkan baik memerlukan mekanisme terpisah (mis. usingkata kunci C # ) atau kode pembersihannya berjalan non-deterministik.

Perhatikan bahwa salah satu kunci untuk GC kinerja tinggi adalah bahwa harus ada dukungan bahasa untuk kelas referensi khusus. C tidak memiliki dukungan bahasa ini dan tidak akan pernah; karena C ++ memiliki overloading operator, ini dapat mengemulasi tipe pointer GC, meskipun itu harus dilakukan dengan hati-hati. Bahkan, ketika Microsoft menemukan dialek C ++ yang akan berjalan di bawah CLR (.NET runtime), mereka harus menciptakan sintaks baru untuk "referensi gaya C #" (mis. Foo^) Untuk membedakan mereka dari "referensi gaya C ++" (mis Foo&.).

Apa yang dimiliki C ++, dan apa yang secara teratur digunakan oleh para programmer C ++, adalah pointer cerdas , yang sebenarnya hanyalah mekanisme penghitungan referensi. Saya tidak akan menganggap penghitungan referensi sebagai GC "benar", tetapi memberikan banyak manfaat yang sama, dengan biaya kinerja yang lebih lambat daripada manajemen memori manual atau GC benar, tetapi dengan keuntungan dari kerusakan deterministik.

Pada akhirnya, jawabannya benar-benar bermuara pada fitur desain bahasa. C membuat satu pilihan, C ++ membuat pilihan yang memungkinkannya kompatibel dengan C sambil tetap memberikan alternatif yang cukup baik untuk sebagian besar tujuan, dan Java dan C # membuat pilihan lain yang tidak kompatibel dengan C tetapi juga cukup baik untuk sebagian besar tujuan. Sayangnya, tidak ada peluru perak, tetapi terbiasa dengan berbagai pilihan di luar sana akan membantu Anda memilih yang benar untuk program apa pun yang sedang Anda coba buat.


4
Ini adalah jawaban aktual untuk pertanyaan
coredump

1
Untuk bagian c ++, saat ini Anda harus melihat std :: unique_ptr dan std :: move :)
Niclas Larsson

@ NiclasLarsson: Saya tidak yakin saya mengerti maksud Anda. Apakah Anda mengatakan bahwa itu std::unique_ptradalah "dukungan tingkat bahasa untuk referensi yang tidak jelas"? (Itu bukan jenis dukungan yang saya maksud, dan saya juga tidak berpikir itu cukup kecuali dukungan untuk manipulasi memori langsung juga dihapus dari C ++.) Saya memang menyebutkan smart pointer dalam jawaban saya, dan saya akan mempertimbangkan std:unique_ptrsmart pointer , karena ia benar-benar melakukan penghitungan referensi, itu hanya mendukung kasus-kasus khusus di mana jumlah referensi adalah nol atau satu (dan std::movemerupakan mekanisme pemutakhiran penghitungan referensi).
Daniel Pryden

std::unique_ptrtidak memiliki jumlah referensi dan std::movetidak ada hubungannya sama sekali dengan referensi (jadi "tidak" ada performa). Saya mengerti maksud Anda, seperti std::shared_ptrhalnya memiliki jumlah referensi yang implikasi diperbarui oleh std::move:)
Niclas Larsson

2
@ Mike76: Di sisi alokasi, pengalokasi GC akan bekerja secepat alokasi stack, dan GC dapat membatalkan alokasi ribuan objek pada saat yang sama. Apa pun yang Anda lakukan dengan implementasi penghitungan ulang, alokasi dan alokasi tidak akan pernah lebih cepat dari mallocdan free. Jadi ya, GC bisa jauh lebih cepat. (Perhatikan bahwa saya mengatakan "bisa" - tentu saja kinerja yang tepat dari setiap program dipengaruhi oleh banyak faktor.)
Daniel Pryden

27

Karena, ketika menggunakan kekuatan C ++, tidak perlu.

Herb Sutter: " Sudah bertahun-tahun saya tidak menghapus tulisan. "

lihat Menulis kode C ++ modern: bagaimana C ++ telah berkembang selama bertahun-tahun 21:10

Ini mungkin mengejutkan banyak programmer C ++ yang berpengalaman.


Menarik. Bahan bacaan saya untuk hari ini.
surfasb

Bah, sebuah video. Tapi tidak pernah kalah, sudah menarik.
surfasb

2
video yang menarik. 21 menit, dan 55 menit adalah bit terbaik. Sayang sekali panggilan WinRT masih terlihat sebagai C ++ / CLI bumpf.
gbjbaanb

2
@ dan04: Itu benar. Tetapi kemudian, jika Anda menulis dalam C, Anda mendapatkan apa yang Anda minta.
DeadMG

6
Mengelola pointer pintar tidak lebih menuntut daripada memastikan Anda tidak memiliki referensi yang tidak perlu di lingkungan pengumpulan sampah. Karena GC tidak dapat membaca pikiran Anda, itu juga bukan sihir.
Tamás Szelei

15

"Semua" seorang pemulung adalah proses yang berjalan secara berkala memeriksa untuk melihat apakah ada objek yang tidak direferensikan dalam memori dan jika ada menghapusnya. (Ya, saya tahu ini adalah penyederhanaan yang berlebihan). Ini bukan properti bahasa, tetapi kerangka kerja.

Ada pengumpul sampah yang ditulis untuk C dan C ++ - yang ini misalnya.

Salah satu alasan mengapa seseorang belum "ditambahkan" ke bahasa ini mungkin karena banyaknya volume kode yang ada yang tidak akan pernah menggunakannya karena mereka menggunakan kode mereka sendiri untuk mengelola memori. Alasan lain bisa jadi jenis aplikasi yang ditulis dalam C dan C ++ tidak perlu overhead yang terkait dengan proses pengumpulan sampah.


1
Tetapi program-program mendatang yang ditulis akan mulai menggunakan pengumpul sampah, bukan?
Dark Templar

5
Sementara pengumpulan sampah secara teoritis independen dari bahasa pemrograman apa pun, cukup sulit untuk menulis GC yang berguna untuk C / C ++, dan bahkan tidak mungkin untuk membuat yang bodoh-bukti (setidaknya sama mudahnya dengan Jawa) - alasan Jawa dapat menariknya off karena berjalan dalam lingkungan tervirtualisasi yang terkendali. Sebaliknya, bahasa Java dirancang untuk GC, dan Anda akan kesulitan menulis kompiler Java yang tidak melakukan GC.
tdammers

4
@tdammers: Saya setuju bahwa pengumpulan sampah perlu didukung oleh bahasa agar memungkinkan. Namun, poin utama bukanlah virtualisasi dan lingkungan terkontrol, tetapi pengetikan yang ketat. C dan C ++ diketik dengan lemah, sehingga mereka memungkinkan hal-hal seperti menyimpan pointer dalam variabel integer, merekonstruksi pointer dari offset dan hal-hal seperti itu yang mencegah kolektor untuk dapat mengatakan dengan andal apa yang dapat dijangkau (C ++ 11 melarang yang lebih baru untuk memungkinkan setidaknya kolektor konservatif). Di Jawa Anda selalu tahu apa itu referensi, sehingga Anda bisa mengumpulkannya dengan tepat, bahkan jika dikompilasi ke asli.
Jan Hudec

2
@ ThorbjørnRavnAndersen: Saya dapat menulis program C yang valid yang menyimpan pointer sedemikian rupa sehingga tidak ada pemulung yang bisa menemukannya. Jika Anda mengaitkan seorang pemulung ke mallocdan free, Anda akan merusak program saya yang benar.
Ben Voigt

2
@ ThorbjørnRavnAndersen: Tidak, saya tidak akan menelepon freesampai saya selesai dengan itu. Tapi pengumpul sampah yang Anda usulkan yang tidak membebaskan memori sampai saya secara eksplisit menelepon freebukan pengumpul sampah sama sekali.
Ben Voigt

12

C dirancang di era ketika pengumpulan sampah nyaris bukan pilihan. Itu juga dimaksudkan untuk kegunaan di mana pengumpulan sampah umumnya tidak akan bekerja - logam kosong, lingkungan waktu nyata dengan memori minimal dan dukungan runtime minimal. Ingat bahwa C adalah bahasa implementasi untuk unix pertama, yang berjalan pada pdp-11 dengan 64 * K * byte memori. C ++ awalnya merupakan perluasan ke C - pilihan sudah dibuat, dan sangat sulit untuk mencangkokkan pengumpulan sampah ke bahasa yang ada. Ini adalah hal yang harus dibangun dari lantai dasar.


9

Saya tidak memiliki kutipan yang tepat, tetapi baik Bjarne dan Herb Sutter mengatakan sesuatu seperti itu:

C ++ tidak memerlukan pemulung, karena tidak memiliki sampah.

Dalam C ++ modern Anda menggunakan pointer pintar dan karenanya tidak memiliki sampah.


1
apa itu smart pointer?
Dark Templar

11
jika sesederhana itu, tidak ada yang akan menerapkan GC.
deadalnix

7
@deadalnix: Benar, karena tidak ada yang pernah mengimplementasikan sesuatu yang terlalu rumit, lambat, kembung, atau tidak perlu. Semua perangkat lunak 100% efisien setiap saat, bukan?
Zach

5
@deadalnix - Pendekatan C ++ untuk manajemen memori lebih baru daripada pengumpul sampah. RAII ditemukan oleh Bjarne Stroustrup untuk C ++. Pembersihan destruktor adalah ide yang lebih tua, tetapi aturan untuk memastikan keamanan pengecualian adalah kunci. Saya tidak tahu kapan tepatnya kapan ide itu pertama kali dijelaskan tetapi standar C ++ pertama diselesaikan pada tahun 1998, dan Stroustrups "Desain dan Evolusi C ++" tidak diterbitkan sampai 1994, dan pengecualian adalah tambahan yang relatif baru untuk C ++ - setelah penerbitan "Manual Referensi C ++ Beranotasi" pada tahun 1990, saya percaya. GC ditemukan pada tahun 1959 untuk Lisp.
Steve314

1
@deadalnix - apakah Anda sadar bahwa setidaknya satu Java VM menggunakan penghitungan referensi GC yang dapat (hampir) diimplementasikan menggunakan C ++ - style RAII menggunakan smart pointer class - justru karena lebih efisien untuk kode multithreaded daripada VM yang ada? Lihat www.research.ibm.com/people/d/dfb/papers/Bacon01Concurrent.pdf. Salah satu alasan Anda tidak melihat ini dalam C ++ dalam praktiknya adalah pengumpulan GC biasa - ia dapat mengumpulkan siklus, tetapi tidak dapat memilih urutan destruktor yang aman di hadapan siklus, dan dengan demikian tidak dapat memastikan pembersihan destruktor yang andal.
Steve314

8

Anda bertanya mengapa bahasa ini belum diperbarui untuk menyertakan pengumpul sampah opsional.

Masalah dengan pengumpulan sampah opsional adalah Anda tidak dapat mencampur kode yang menggunakan model yang berbeda. Artinya, jika saya menulis kode yang mengasumsikan Anda menggunakan pengumpul sampah, Anda tidak dapat menggunakannya dalam program Anda yang pengumpulan sampahnya dimatikan. Jika Anda melakukannya, itu akan bocor ke mana-mana.


6

Bisakah Anda bayangkan menulis penangan perangkat dalam bahasa dengan pengumpulan sampah? Berapa banyak bit yang bisa turun saat GC sedang berjalan?

Atau sistem operasi? Bagaimana Anda bisa memulai pengumpulan sampah yang berjalan bahkan sebelum Anda memulai kernel?

C dirancang untuk level rendah dekat dengan tugas perangkat keras. Masalah? apakah itu bahasa yang bagus sehingga merupakan pilihan yang baik untuk banyak tugas tingkat yang lebih tinggi juga. Bahasa tsar menyadari penggunaan ini tetapi mereka perlu mendukung persyaratan driver perangkat, kode tertanam dan sistem operasi sebagai prioritas.


2
C bagus untuk level tinggi? Saya mendengus minuman saya di seluruh keyboard saya.
DeadMG

5
Yah, dia memang mengatakan "banyak tugas tingkat yang lebih tinggi". Dia bisa menghitung troll (satu, dua, banyak ...). Dan dia tidak benar-benar mengatakan lebih tinggi dari apa. Lelucon samping, meskipun, itu benar - bukti adalah bahwa banyak proyek yang lebih tinggi tingkat signifikan telah berhasil dikembangkan di C. Mungkin ada pilihan yang lebih baik sekarang ke banyak proyek-proyek tersebut, tetapi proyek bekerja bukti kuat dari spekulasi tentang apa yang mungkin telah.
Steve314

Ada beberapa sistem operasi yang dikelola, dan mereka bekerja dengan baik. Bahkan, ketika Anda membuat seluruh sistem dikelola, kinerja yang dihasilkan dari menggunakan kode terkelola turun lebih rendah, hingga menjadi lebih cepat daripada kode yang tidak dikelola dalam skenario kehidupan nyata. Tentu saja, semua itu adalah "OS riset" - hampir tidak ada cara untuk membuatnya kompatibel dengan kode yang tidak dikelola yang ada selain membuat OS yang tidak dikelola sepenuhnya tervirtualisasi dalam OS yang dikelola. Microsoft memang menyarankan pada beberapa titik bahwa mereka mungkin mengganti Windows Server dengan salah satu dari mereka, meskipun, karena semakin banyak kode server ditulis di .NET.
Luaan

6

Jawaban singkat dan membosankan untuk pertanyaan ini adalah bahwa perlu ada bahasa yang dikumpulkan non-sampah di luar sana untuk orang-orang yang menulis pengumpul sampah. Secara konseptual tidak mudah untuk memiliki bahasa yang pada saat yang sama memungkinkan untuk kontrol yang sangat tepat atas tata letak memori dan memiliki GC yang berjalan di atas.

Pertanyaan lainnya adalah mengapa C dan C ++ tidak memiliki pemulung. Yah, saya tahu C ++ memiliki beberapa dari mereka di sekitar tetapi mereka tidak benar-benar populer karena mereka dipaksa untuk berurusan dengan bahasa yang tidak dirancang untuk menjadi GC-ed di tempat pertama, dan orang-orang yang masih menggunakan C ++ di usia ini sebenarnya bukan jenis yang merindukan GC.

Selain itu, alih-alih menambahkan GC ke bahasa non-GC-ed lama, sebenarnya lebih mudah untuk membuat bahasa baru yang memiliki sebagian besar sintaksis yang sama sambil mendukung GC. Java dan C # adalah contoh yang bagus untuk ini.


1
Di suatu tempat di programmer.se atau SO, ada klaim seseorang mengatakan kepada saya bahwa seseorang sedang mengerjakan sesuatu yang dikumpulkan dengan boot-booting sendiri - IIRC pada dasarnya mengimplementasikan VM menggunakan bahasa GC, dengan subset bootstrap yang digunakan untuk mengimplementasikan GC itu sendiri. Saya lupa namanya. Ketika saya melihat ke dalamnya, ternyata mereka pada dasarnya tidak pernah mencapai lompatan dari subset-tanpa-GC ke tingkat kerja-GC. Ini adalah mungkin pada prinsipnya, tapi AFAIK itu belum pernah dicapai dalam praktek - itu pasti kasus melakukan hal-hal dengan cara yang keras.
Steve314

@ Steve314: Saya ingin sekali melihatnya jika Anda ingat di mana Anda menemukannya!
hugomg

menemukannya! Lihat komentar untuk stackoverflow.com/questions/3317329/… mengacu pada Klein VM. Bagian dari masalah menemukannya - pertanyaannya sudah ditutup.
Steve314

BTW - Saya sepertinya tidak dapat memulai komentar saya dengan @missingno - apa yang terjadi?
Steve314

@ steve314: Setelah menulis jawaban utas ini dilampirkan, saya sudah menerima pemberitahuan untuk semua komentar. Melakukan @ -pos dalam hal ini akan menjadi berlebihan dan tidak diizinkan oleh SE (jangan tanya kenapa ). (Penyebab sebenarnya adalah karena nomor saya tidak ada)
hugomg

5

Ada berbagai masalah, termasuk ...

  • Meskipun GC ditemukan sebelum C ++, dan mungkin sebelum C, baik C dan C ++ diimplementasikan sebelum GC diterima secara luas sebagai praktis.
  • Anda tidak dapat dengan mudah mengimplementasikan bahasa dan platform GC tanpa bahasa non-GC yang mendasarinya.
  • Meskipun GC terbukti lebih efisien daripada non-GC untuk kode aplikasi tipikal yang dikembangkan dalam rentang waktu tertentu, dll., Ada masalah di mana upaya pengembangan yang lebih baik merupakan pertukaran yang baik dan manajemen memori khusus akan mengungguli GC tujuan umum. Selain itu, C ++ biasanya terbukti lebih efisien daripada kebanyakan bahasa GC bahkan tanpa upaya pengembangan tambahan.
  • GC tidak lebih aman dari RAII gaya C ++. RAII memungkinkan sumber daya selain memori untuk dibersihkan secara otomatis, pada dasarnya karena mendukung destruktor yang andal dan tepat waktu. Ini tidak dapat dikombinasikan dengan metode GC konvensional karena masalah dengan siklus referensi.
  • Bahasa-bahasa GC memiliki jenis kebocoran memori yang khas, khususnya yang berkaitan dengan memori yang tidak akan pernah digunakan lagi, tetapi di mana ada referensi yang belum pernah dihapus atau ditimpa. Kebutuhan untuk melakukan ini secara eksplisit tidak berbeda dari prinsipnya dengan kebutuhan deleteatau freesecara eksplisit. Pendekatan GC masih memiliki keunggulan - tidak ada referensi yang menggantung - dan analisis statis dapat menangkap beberapa kasus, tetapi sekali lagi, tidak ada satu solusi sempurna untuk semua kasus.

Pada dasarnya, sebagian adalah tentang usia bahasa, tetapi akan selalu ada tempat untuk bahasa non-GC - bahkan jika itu adalah sedikit tempat nichey. Dan serius, di C ++, kurangnya GC bukanlah masalah besar - memori Anda dikelola secara berbeda, tetapi tidak dikelola.

Microsoft mengelola C ++ memiliki setidaknya beberapa kemampuan untuk mencampur GC dan non-GC dalam aplikasi yang sama, memungkinkan campuran dan kecocokan dari keuntungan masing-masing, tetapi saya tidak memiliki pengalaman untuk mengatakan seberapa baik ini bekerja dalam prakteknya.

Tautan pelaporan ulang ke jawaban terkait saya ...


4

Pengumpulan sampah pada dasarnya tidak kompatibel dengan bahasa sistem yang digunakan untuk mengembangkan driver untuk perangkat keras yang mendukung DMA.

Sangat mungkin bahwa satu-satunya pointer ke objek akan disimpan dalam register perangkat keras di beberapa perangkat. Karena pengumpul sampah tidak akan tahu tentang ini, itu akan berpikir benda itu tidak dapat dijangkau dan mengumpulkannya.

Argumen ini berlaku ganda untuk memadatkan GC. Bahkan jika Anda berhati-hati untuk mempertahankan referensi dalam memori ke objek yang digunakan oleh periferal perangkat keras, ketika GC memindahkan objek, ia tidak akan tahu cara memperbarui pointer yang terdapat dalam register konfigurasi perifer.

Jadi sekarang Anda akan membutuhkan campuran buffer DMA bergerak dan objek yang dikelola GC, yang berarti Anda memiliki semua kelemahan dari keduanya.


Bisa dibilang semua kerugian dari keduanya, tetapi lebih sedikit contoh masing-masing kelemahan, dan sama untuk keuntungan. Jelas ada kerumitan dalam memiliki lebih banyak jenis manajemen memori untuk ditangani, tetapi mungkin juga ada kompleksitas dihindari dengan memilih kuda yang tepat untuk setiap kursus dalam kode Anda. Tidak mungkin, saya bayangkan, tetapi ada kesenjangan teoretis di sana. Saya berspekulasi tentang pencampuran GC dan non-GC dalam bahasa yang sama sebelumnya, tetapi tidak untuk driver perangkat - lebih karena memiliki sebagian besar aplikasi GC, tetapi dengan beberapa perpustakaan struktur data tingkat rendah yang dikelola secara memori.
Steve314

@ Steve314: Tidakkah Anda mengatakan bahwa mengingat objek mana yang perlu dibebaskan secara manual sama sulitnya dengan mengingat untuk membebaskan semuanya? (Tentu saja, smart pointer dapat membantu dengan baik, jadi tidak ada yang merupakan masalah besar) Dan Anda membutuhkan kumpulan berbeda untuk objek yang dikelola secara manual vs objek yang dikumpulkan / dipadatkan, karena pemadatan tidak berfungsi dengan baik ketika ada objek tetap yang tersebar di seluruh. Jadi banyak kerumitan ekstra untuk apa-apa.
Ben Voigt

2
Tidak jika ada perbedaan yang jelas antara kode tingkat tinggi yang semuanya merupakan GC, dan kode tingkat rendah yang memilih keluar dari GC. Saya terutama mengembangkan ide sambil melihat D beberapa tahun yang lalu, yang memungkinkan Anda untuk memilih keluar dari GC tetapi tidak memungkinkan Anda untuk memilih kembali. Ambil contoh perpustakaan pohon B +. Wadah secara keseluruhan harus GC, tetapi node struktur data mungkin tidak - lebih efisien untuk melakukan pemindaian khusus melalui node daun hanya daripada membuat GC melakukan pencarian secara rekursif melalui node cabang. Namun, pemindaian itu perlu melaporkan item yang terkandung ke GC.
Steve314

Intinya adalah, itu bagian fungsionalitas yang terkandung. Mengobati node B + tree sebagai manajemen memori WRT khusus tidak berbeda untuk memperlakukan mereka sebagai WRT khusus menjadi node B + tree. Ini adalah pustaka yang dienkapsulasi, dan kode aplikasi tidak perlu tahu bahwa perilaku GC telah di-bypass / dibuat khusus. Kecuali itu, setidaknya pada saat itu, itu tidak mungkin dalam D - seperti yang saya katakan, tidak ada cara untuk memilih kembali dan melaporkan barang yang terkandung ke GC sebagai potensi akar GC.
Steve314

3

Karena, C&C ++ adalah bahasa tingkat relatif rendah yang dimaksudkan untuk tujuan umum, bahkan, misalnya, untuk berjalan pada prosesor 16-bit dengan memori 1MB dalam sistem tertanam, yang tidak mampu membuang-buang memori dengan gc.


1
"Sistem tertanam"? Pada saat C distandarisasi (1989), ia harus mampu menangani PC dengan memori 1 MB.
dan04

Saya setuju, saya mengutip contoh yang lebih terkini.
Petruza

1MB ??? Astaga, siapa yang akan membutuhkan RAM sebanyak itu? </billGates>
Mark K Cowan

2

Ada pengumpul sampah di C ++ dan C. Tidak yakin bagaimana ini bekerja di C, tetapi di C ++ Anda dapat memanfaatkan RTTI untuk secara dinamis menemukan grafik objek Anda dan menggunakannya untuk pengumpulan sampah.

Sepengetahuan saya, Anda tidak dapat menulis Java tanpa pengumpul sampah. Pencarian kecil muncul ini .

Perbedaan utama antara Java dan C / C ++ adalah bahwa dalam C / C ++ pilihan selalu menjadi milik Anda, sedangkan di Jawa Anda sering dibiarkan tanpa opsi oleh desain.


Dan juga bahwa pengumpul sampah khusus diimplementasikan dengan lebih baik, lebih efisien dan lebih cocok dalam bahasa. :)
Maks.

Tidak, Anda tidak dapat menggunakan RTTI untuk secara dinamis menemukan grafik objek di C / C ++: Ini adalah objek data lama yang sederhana yang merusak segalanya. Tidak ada informasi RTTI yang disimpan dalam objek data lama biasa yang akan memungkinkan pengumpul sampah untuk membedakan antara pointer dan non-pointer dalam objek itu. Lebih buruk lagi, pointer tidak perlu disejajarkan dengan sempurna pada semua perangkat keras, jadi, mengingat objek 16 byte, ada 9 lokasi yang memungkinkan pointer 64 bit dapat disimpan, hanya dua yang tidak tumpang tindih.
cmaster

2

Ini merupakan trade off antara kinerja dan keselamatan.

Tidak ada jaminan bahwa sampah Anda akan dikumpulkan di Jawa, jadi itu mungkin berkeliaran menghabiskan ruang untuk waktu yang lama, sementara pemindaian untuk objek yang tidak direferensikan (yaitu sampah) juga membutuhkan waktu lebih lama daripada secara eksplisit menghapus atau membebaskan objek yang tidak digunakan.

Keuntungannya, tentu saja, bahwa seseorang dapat membangun bahasa tanpa petunjuk atau tanpa kebocoran memori, sehingga seseorang lebih mungkin untuk menghasilkan kode yang benar.

Kadang-kadang ada sedikit 'religius' perdebatan ini - diperingatkan!


1

Berikut adalah daftar masalah inheren GC, yang membuatnya tidak dapat digunakan dalam bahasa sistem seperti C:

  • GC harus dijalankan di bawah level kode yang objeknya dikelola. Tidak ada level seperti itu di kernel.

  • GC harus menghentikan kode yang dikelola dari waktu ke waktu. Sekarang pikirkan apa yang akan terjadi jika hal itu terjadi pada kernel Anda. Semua pemrosesan pada mesin Anda akan berhenti selama, katakanlah, satu milidetik, sementara GC memindai semua alokasi memori yang ada. Ini akan mematikan semua upaya untuk menciptakan sistem yang beroperasi di bawah persyaratan waktu nyata yang ketat.

  • GC perlu dapat membedakan antara pointer dan non-pointer. Artinya, ia harus dapat melihat setiap objek memori yang ada, dan dapat menghasilkan daftar offset di mana pointer-nya dapat ditemukan.

    Penemuan ini harus sempurna: GC harus mampu mengejar semua petunjuk yang ditemukannya. Jika dereferensi positif palsu, kemungkinan akan crash. Jika gagal menemukan negatif palsu, kemungkinan akan menghancurkan objek yang masih digunakan, menabrak kode yang dikelola atau merusak data secara diam-diam.

    Ini benar-benar mengharuskan informasi jenis disimpan di setiap objek tunggal yang ada. Namun, baik C dan C ++ memungkinkan objek data lama polos yang tidak berisi informasi tipe.

  • GC adalah bisnis yang pada dasarnya lambat. Programmer yang telah disosialisasikan dengan Java mungkin tidak menyadari hal ini, tetapi program dapat menjadi urutan besarnya lebih cepat ketika mereka tidak diimplementasikan di Jawa. Dan salah satu faktor yang membuat Java lambat adalah GC. Inilah yang menghalangi bahasa-bahasa GCed seperti Java agar tidak digunakan dalam superkomputer. Jika mesin Anda menghabiskan satu juta tahun dalam konsumsi daya, Anda tidak ingin membayar bahkan 10% dari itu untuk pengumpulan sampah.

C dan C ++ adalah bahasa yang dibuat untuk mendukung semua kasus penggunaan yang mungkin. Dan, seperti yang Anda lihat, banyak dari kasus penggunaan ini dihambat oleh pengumpulan sampah. Jadi, untuk mendukung kasus penggunaan ini, C / C ++ tidak dapat dikumpulkan sebagai sampah.

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.