Buradaki tartışmaya eklemek için.
Çöp toplama ile ilgili bilinen sorunlar vardır ve bunları anlamak, C ++ 'da neden yok olduğunu anlamaya yardımcı olur.
1. Performans?
İlk şikayet genellikle performansla ilgilidir, ancak çoğu insan ne hakkında konuştuklarını gerçekten bilmez. Tarafından gösterildiği gibi Martin Beckett
, kendi başına performansı, ama performans tahmin edilebilir olmayabilir sorun.
Şu anda yaygın olarak konuşlandırılan 2 GC ailesi var:
- İşaretle ve Tara tipi
- Referans Sayma türü
Daha Mark And Sweep
hızlıdır (genel performans üzerinde daha az etki), ancak "dünyayı dondur" sendromundan muzdariptir: yani GC devreye girdiğinde, GC temizliğini yapana kadar her şey durdurulur. Birkaç milisaniyede cevap veren bir sunucu oluşturmak isterseniz ... bazı işlemler beklentilerinize uygun olmayacaktır :)
Sorunu Reference Counting
farklıdır: referans sayma, özellikle Çoklu İş parçacığı ortamlarında ek yük ekler, çünkü atom sayımına ihtiyacınız vardır. Ayrıca referans döngüleri problemi vardır, bu nedenle bu döngüleri tespit etmek ve ortadan kaldırmak için akıllı bir algoritmaya ihtiyacınız vardır (genellikle daha az sıklıkta olsa da "dünyayı dondur" ile de uygulayın). Genel olarak, bugün itibariyle, bu tür (normalde daha duyarlı veya daha doğrusu, daha az sıklıkta donma olsa da) daha yavaştır Mark And Sweep
.
Eyfel uygulayıcıları tarafından , "Dünyayı Dondur" yönü olmadan Reference Counting
benzer bir küresel performansa sahip olacak bir Çöp Toplayıcıyı uygulamaya çalışan bir makale gördüm Mark And Sweep
. GC için ayrı bir diş gerektiriyordu (tipik). Algoritma biraz korkutucuydu (sonunda) ancak kağıt kavramları birer birer tanıtmak ve algoritmanın "basit" versiyondan tam teşekküllü olana evrimini göstermek için iyi bir iş çıkardı. PDF dosyama ellerimi geri koyabilseydim tavsiye edilir ...
2. Kaynak Alımı Başlatılıyor (RAII)
C++
Kaynakların sahipliğini düzgün bir şekilde serbest bırakıldığından emin olmak için bir nesnenin içindeki mülkiyeti sarmanız yaygın bir deyimdir . Çöp koleksiyonumuz olmadığından çoğunlukla bellek için kullanılır, ancak yine de diğer birçok durum için yararlıdır:
- kilitler (çoklu iş parçacığı, dosya tanıtıcısı, ...)
- bağlantıları (bir veritabanına, başka bir sunucuya, ...)
Fikir, nesnenin ömrünü düzgün bir şekilde kontrol etmektir:
- ihtiyacınız olduğu sürece hayatta olmalı
- işiniz bittiğinde öldürülmeli
GC sorunu, eğer öncekine yardım ederse ve sonuçta daha sonra ... bu "nihai" nin yeterli olmayabileceğini garanti ederse. Bir kilidi bırakırsanız, kilidin şimdi serbest bırakılmasını istersiniz, böylece başka çağrıları engellemez!
GC'li dillerde iki çözüm vardır:
- yığın tahsisi yeterli olduğunda GC kullanmayın: normalde performans sorunları içindir, ancak bizim durumumuzda kapsam ömrünü tanımladığı için gerçekten yardımcı olur
using
yapı ... ancak C ++ RAII'de açıkken (zayıf) RAII örtüktür, böylece kullanıcı farkında olmadan hata YAPAMAZ ( using
anahtar sözcüğü atlayarak )
3. Akıllı İşaretçiler
Akıllı işaretçiler genellikle belleği işlemek için gümüş bir kurşun gibi görünür C++
. Çoğu zaman duydum: sonuçta GC'ye ihtiyacımız yok, çünkü akıllı işaretçilerimiz var.
Daha yanlış olamazdı.
Akıllı işaretçiler yardımcı olur: auto_ptr
ve unique_ptr
gerçekten son derece kullanışlı olan RAII kavramlarını kullanın. O kadar basittir ki, bunları kendiniz kolayca yazabilirsiniz.
Sahipliği paylaşmak gerektiğinde daha da zorlaşırsa: birden fazla iş parçacığı arasında paylaşabilirsiniz ve sayımın ele alınmasında birkaç küçük sorun vardır. Bu nedenle, doğal olarak doğru gider shared_ptr
.
Harika, sonuçta Boost bu, ama gümüş bir kurşun değil. Aslında, asıl mesele, shared_ptr
tarafından uygulanan bir GC'yi taklit etmesidir, Reference Counting
ancak döngü algılamayı tek başına uygulamanız gerekir ...
Tabii ki bu var weak_ptr
şey var, ama maalesef shared_ptr
bu döngüler nedeniyle kullanılmasına rağmen bellek sızıntıları gördüm ... ve Çok Dişli bir ortamda olduğunuzda, tespit etmek son derece zordur!
4. çözüm nedir?
Gümüş mermi yok, ama her zamanki gibi kesinlikle mümkün. GC'nin yokluğunda, sahiplik konusunda net olmak gerekir:
- mümkünse belirli bir zamanda tek bir sahibin olmasını tercih edin
- değilse, sınıf diyagramınızın sahiplikle ilgili herhangi bir döngüsüne sahip olmadığından emin olun ve
weak_ptr
Gerçekten de, bir GC'ye sahip olmak harika olurdu ... ancak önemsiz bir sorun değil. Ve bu arada, sadece kolları sıvamamız gerekiyor.