Jenis Pengumpulan Sampah apa yang digunakan Go?

111

Go adalah bahasa pengumpulan sampah:

http://golang.org/doc/go_faq.html#garbage_collection

Di sini dikatakan bahwa ini adalah pengumpul sampah mark-and-sweep, tetapi tidak menyelidiki detailnya, dan penggantinya sedang dikerjakan ... namun, paragraf ini tampaknya belum banyak diperbarui sejak Go dirilis.

Masih mark-and-sweep? Apakah konservatif atau tepat? Apakah ini bersifat generasi?

pengguna1003432
sumber
2
Untuk diskusi panjang tentang sejarah pengumpul sampah Go hingga Juli 2018, lihat blog.golang.org/ismmkeynote
Wildcard

Jawaban:

117

Paket untuk Go 1.4+ pengumpul sampah:

  • hybrid stop-the-world / concurrent collector
  • stop-the-world part dibatasi oleh tenggat waktu 10ms
  • Inti CPU yang didedikasikan untuk menjalankan pengumpul bersamaan
  • algoritma tanda-dan-sapuan tiga warna
  • non-generasi
  • non-pemadatan
  • sangat tepat
  • menimbulkan sedikit biaya jika program memindahkan petunjuk
  • latensi yang lebih rendah, tetapi kemungkinan besar juga lebih rendah daripada Go 1.3 GC

Go 1.3 pembaruan pengumpul sampah di atas Go 1.1:

  • sapuan bersamaan (menghasilkan waktu jeda yang lebih singkat)
  • sangat tepat

Go 1.1 pengumpul sampah:

  • mark-and-sweep (implementasi paralel)
  • non-generasi
  • non-pemadatan
  • sebagian besar tepat (kecuali bingkai tumpukan)
  • stop-the-world
  • representasi berbasis bitmap
  • tanpa biaya ketika program tidak mengalokasikan memori (yaitu: mengacak pointer secepat di C, meskipun dalam praktiknya ini berjalan agak lebih lambat daripada C karena kompiler Go tidak semaju kompiler C seperti GCC)
  • mendukung finalisator pada objek
  • tidak ada dukungan untuk referensi yang lemah

Go 1.0 pengumpul sampah:

  • sama seperti Go 1.1, tetapi bukannya tepat, pengumpul sampah lebih konservatif. GC konservatif dapat mengabaikan objek seperti [] byte.

Mengganti GC dengan yang berbeda kontroversial, misalnya:

  • kecuali untuk tumpukan yang sangat besar, tidak jelas apakah GC generasi akan lebih cepat secara keseluruhan
  • paket "tidak aman" menyulitkan penerapan GC yang sepenuhnya tepat dan GC pemadatan

sumber
Juga pengumpul sampah saat ini memiliki derajat paralelisme tertentu sehingga dapat berjalan lebih cepat pada sistem multi-inti.
uriel
3
@uriel: Ya, saya menyebutkan ini di item pertama dalam jawaban saya - teks "(implementasi paralel)".
Apakah jawaban ini masih terkini?
Kim Stebel
c # pengumpul sampah tepat dan di c # seperti di go Anda dapat memiliki referensi ke anggota terpukul dan c # memiliki mode tidak aman tetapi saya tidak yakin bagaimana perbandingannya dengan implementasi yang tidak aman
skyde
3
Bagaimana dengan memperbarui jawaban ini dengan 1.5.x hanya untuk membuat catatan riwayat yang baik.
Ismael
32

(Untuk Go 1.8 - Q1 2017, lihat di bawah )

Pengumpul Sampah serentak Go 1.5 berikutnya melibatkan kemampuan untuk "memacu" kata gc.
Berikut adalah proposal yang disajikan dalam makalah ini yang mungkin cocok untuk Go 1.5, tetapi juga membantu memahami GC di Go.

Anda dapat melihat keadaan sebelum 1,5 (Stop The World: STW)

Sebelum Go 1.5, Go telah menggunakan pengumpul stop-the-world (STW) paralel .
Meskipun koleksi STW memiliki banyak kelemahan, koleksi STW setidaknya memiliki perilaku pertumbuhan heap yang dapat diprediksi dan dikontrol.

https://40.media.tumblr.com/49e6556b94d75de1050c62539680fcf9/tumblr_inline_nr6qq8D9FE1sdck2n_540.jpg

(Foto dari presentasi GopherCon 2015 " Go GC: Memecahkan Masalah Latensi di Go 1.5 ")

Tombol tuning tunggal untuk kolektor STW adalah "GOGC", pertumbuhan heap relatif antar koleksi. Setelan default, 100%, memicu pengumpulan sampah setiap kali ukuran heap menjadi dua kali lipat dari ukuran live heap seperti pada koleksi sebelumnya:

https://docs.google.com/drawings/image?id=sLJ_JvGfPfPnojLlEGLCWkw&rev=1&h=113&w=424&ac=1

Pengaturan waktu GC di kolektor STW.

Go 1.5 memperkenalkan kolektor bersamaan .
Ini memiliki banyak keuntungan dibandingkan kumpulan STW, tetapi ini membuat pertumbuhan heap lebih sulit dikendalikan karena aplikasi dapat mengalokasikan memori saat pengumpul sampah sedang berjalan .

https://40.media.tumblr.com/783c6e557b427a5c023520578740eb94/tumblr_inline_nr6qqpmaJx1sdck2n_540.jpg

(Foto dari presentasi GopherCon 2015 " Go GC: Memecahkan Masalah Latensi di Go 1.5 ")

Untuk mencapai batas pertumbuhan heap yang sama, runtime harus memulai pengumpulan sampah lebih awal, tetapi seberapa jauh sebelumnya bergantung pada banyak variabel, banyak di antaranya tidak dapat diprediksi.

  • Mulai pengumpul terlalu dini, dan aplikasi akan melakukan terlalu banyak pengumpulan sampah, membuang sumber daya CPU.
  • Mulailah pengumpul terlambat, dan aplikasi akan melebihi pertumbuhan heap maksimum yang diinginkan.

Mencapai keseimbangan yang tepat tanpa mengorbankan konkurensi membutuhkan pemindahan sampah yang cermat.

Penentuan tempo GC bertujuan untuk mengoptimalkan dua dimensi: pertumbuhan heap, dan CPU yang digunakan oleh pengumpul sampah.

https://docs.google.com/drawings/image?id=sEZYCf7Mc0E0EGmy4gho3_w&rev=1&h=235&w=457&ac=1

Desain pacu GC terdiri dari empat komponen:

  1. penaksir untuk jumlah pekerjaan pemindaian yang diperlukan siklus GC,
  2. mekanisme bagi mutator untuk melakukan perkiraan jumlah pekerjaan pemindaian pada saat alokasi heap mencapai tujuan heap,
  3. penjadwal untuk pemindaian latar belakang ketika mutator membantu kurang memanfaatkan anggaran CPU, dan
  4. pengontrol proporsional untuk pemicu GC.

Desainnya menyeimbangkan dua tampilan waktu yang berbeda: waktu CPU dan waktu heap .

  • Waktu CPU seperti waktu jam dinding standar, tetapi melewati GOMAXPROCSwaktu lebih cepat.
    Artinya, jika GOMAXPROCS8, maka delapan detik CPU melewati setiap detik dinding dan GC mendapat dua detik waktu CPU setiap detik.
    Penjadwal CPU mengatur waktu CPU.
  • Perjalanan waktu heap diukur dalam byte dan bergerak maju saat mutator mengalokasikan.

Hubungan antara waktu heap dan waktu dinding bergantung pada tingkat alokasi dan dapat berubah secara konstan.
Mutator membantu mengelola perjalanan waktu heap, memastikan perkiraan pekerjaan pemindaian telah diselesaikan pada saat heap mencapai ukuran tujuan.
Terakhir, pengontrol pemicu membuat loop umpan balik yang menghubungkan kedua tampilan waktu ini bersama-sama, mengoptimalkan waktu heap dan tujuan waktu CPU.

VonC
sumber
20

Berikut implementasi GC:

https://github.com/golang/go/blob/master/src/runtime/mgc.go

Dari dokumen di sumber:

GC berjalan secara bersamaan dengan utas mutator, memiliki tipe yang akurat (alias presisi), memungkinkan beberapa utas GC berjalan secara paralel. Ini adalah tanda dan sapuan bersamaan yang menggunakan pembatas tulis. Ini non-generasi dan non-pemadatan. Alokasi dilakukan dengan menggunakan ukuran yang dipisahkan per area alokasi P untuk meminimalkan fragmentasi sekaligus menghilangkan kunci dalam kasus umum.

berdario
sumber
8

Go 1.8 GC mungkin berevolusi lagi, dengan proposal "Hilangkan pemindaian ulang tumpukan STW"

Mulai Go 1.7, satu-satunya sumber waktu stop-the-world (STW) tak terbatas dan berpotensi non-sepele adalah pemindaian ulang tumpukan.

Kami mengusulkan untuk menghilangkan kebutuhan untuk pemindaian ulang tumpukan dengan beralih ke penghalang tulis hibrid yang menggabungkan penghalang tulis penghapusan gaya Yuasa [Yuasa '90] dan penghalang tulis penyisipan gaya Dijkstra [Dijkstra '78] .

Eksperimen pendahuluan menunjukkan bahwa hal ini dapat mengurangi waktu STW kasus terburuk menjadi di bawah 50µs , dan pendekatan ini mungkin membuatnya praktis untuk menghilangkan penghentian tanda STW sama sekali.

The Pengumuman sini dan Anda dapat melihat sumber yang relevan komit d70b0fe dan sebelumnya.

VonC
sumber
3

Saya tidak yakin, tapi saya pikir (tip) GC saat ini sudah paralel atau setidaknya itu WIP. Dengan demikian, properti stop-the-world tidak berlaku lagi atau tidak akan berlaku dalam waktu dekat. Mungkin orang lain dapat mengklarifikasi hal ini lebih detail.

jnml
sumber
7
Ini adalah stop-the-world. GC berpotensi berjalan secara paralel setelah dunia dihentikan. Anda mungkin bermaksud GC bersamaan.