Neyse ki, işaret ettiğiniz gibi, COMPACT Mono yapıları nesilsel bir GC kullanır (sadece düz bir liste tutan WinMo / WinPhone / XBox gibi Microsoft'ların aksine).
Oyununuz basitse GC iyi bir şekilde ele almalıdır, ancak işte bakmak isteyebileceğiniz bazı işaretçiler.
Erken Optimizasyon
İlk olarak, düzeltmeye çalışmadan önce bunun sizin için bir sorun olduğundan emin olun.
Havuzlama Pahalı Referans Türleri
Sık oluşturduğunuz veya derin yapıları olan referans türlerini bir araya getirmelisiniz. Her birine örnek olarak şunlar verilebilir:
Stack
Havuzunuz olarak a kullanmalısınız (a kullanan çoğu uygulamanın aksine Queue
). Bunun nedeni, Stack
bir nesneyi havuza iade ederseniz ve başka bir şey hemen yakalarsa; etkin bir sayfada olma şansınız daha yüksek, hatta şanslıysanız CPU önbelleğinde bile. Sadece biraz daha hızlı. Ayrıca, havuzlarınızı her zaman boyut olarak sınırlayın (sınırınız aşıldıysa 'checkin'leri dikkate almayın).
Temizlemek için Yeni Listeler Oluşturmaktan Kaçının
List
Gerçekten demek istediğinizde yeni bir şey yaratmayın Clear()
. Arka uç dizisini yeniden kullanabilir ve bir dizi dizi ayırma ve kopyasını kaydedebilirsiniz. Buna benzer olarak, anlamlı bir başlangıç kapasitesine sahip listeler oluşturun ve oluşturun (unutmayın, bu bir sınır değildir - sadece bir başlangıç kapasitesi) - doğru olması gerekmez, sadece bir tahmin. Bu, a dışında herhangi bir toplama türü için geçerli olmalıdır LinkedList
.
Mümkün Olduğunda Yapı Dizilerini (veya Listelerini) Kullanın
Nesnelerin arasında dolaşırsanız kullanım yapılarından (veya genel olarak değer türlerinden) çok az kazanç elde edersiniz. Örneğin, çoğu 'iyi' parçacık sisteminde ayrı ayrı parçacıklar büyük bir dizide saklanır: dizi ve indeks parçacığın kendisi yerine geçirilir. Bunun çok iyi çalışmasının nedeni, GC'nin diziyi toplaması gerektiğinde içeriği tamamen atlayabilmesidir (bu ilkel bir dizidir - burada yapacak bir şey yoktur). Yani 10.000 nesneye bakmak yerine GC sadece 1 diziye bakmalıdır: büyük kazanç! Yine, bu sadece değer türleriyle çalışacaktır .
RoyT'tan sonra. bazı daha uygulanabilir ve yapıcı geri bildirim sağladım. Bu tekniği sadece büyük miktarlarda varlıklarla (binlerce ila onbinlerce) uğraşırken kullanmalısınız. Buna ek olarak bu olmalıdır bir yapı olması gerekir herhangi bir referans tipi alanlara sahip ve bir açık-daktilo dizide yaşamalıdır. Geri bildirimlerinin aksine, onu bir sınıftaki bir alan olan bir diziye yerleştiriyoruz - yani yığına inecek (bir yığın tahsisinden kaçınmaya çalışmıyoruz - sadece GC çalışmasından kaçınıyoruz). Gerçekten önemsiyoruz, GC'nin bir O(1)
işlem yerine bir işlemde kolayca bakabileceği birçok değer içeren bitişik bir bellek yığını O(n)
.
GC bu parçaları hareket ettirmeye çalışırken parçalanma veya aşırı çalışma olasılığını azaltmak için bu dizileri uygulama başlangıcınıza mümkün olduğunca yakın olarak ayırmalısınız (ve yerleşik tür yerine karma bağlantılı bir liste kullanmayı düşünmelisiniz) List
).
GC.Collect ()
Bu kesinlikle kendinizi nesiller boyu bir GC ile ayağa vurmanın en iyi yoludur (bakınız: "Performans Konuları"). Sadece EXTREME miktarda çöp oluşturduğunuzda çağırmalısınız - ve bunun bir sorun olabileceği tek örnek, içeriği bir seviye için yükledikten hemen sonradır - ve o zaman bile sadece ilk nesli toplamalısınız ( ) Umarım üçüncü nesile nesnelerin tanıtımını engeller.GC.Collect(0);
IDisposable ve Field Nulling
Artık bir nesneye ihtiyacınız olmadığında alanları boş bırakmaya değer (kısıtlanmış nesnelerde daha fazla). Bunun nedeni, GC'nin nasıl çalıştığının ayrıntılarındadır: geçerli koleksiyonda kaldırılan diğer nesneler nedeniyle bu nesnenin kökleri kaldırılmış olsa bile yalnızca köklenmemiş (yani başvuruda bulunmayan) nesneleri kaldırır ( not: bu, GC'ye bağlıdır kullanılan lezzet - bazıları aslında zincirleri temizler). Ek olarak, bir nesne bir koleksiyonda hayatta kalırsa hemen bir sonraki nesle yükseltilir - bu, toplama sırasında tarlalarda kalan nesnelerin tanıtılacağı anlamına gelir. Her ardışık jenerasyonun toplanması katlanarak daha pahalıdır (ve nadiren meydana gelir).
Aşağıdaki örneği alın:
MyObject (G1) -> MyNestedObject (G1) -> MyFurtherNestedObject (G1)
// G1 Collection
MyNestObject (G2) -> MyFurtherNestedObject (G2)
// G2 Collection
MyFurtherNestedObject (G3)
Eğer MyFurtherNestedObject
yanlışlıkla G3 onu terfi çünkü - çok megabayt nesne içeren GC oldukça uzun bir süre bakmak olmaz garanti edilebilir. Bunu bu örnekle karşılaştırın:
MyObject (G1) -> MyNestedObject (G1) -> MyFurtherNestedObject (G1)
// Dispose
MyObject (G1)
MyNestedObject (G1)
MyFurtherNestedObject (G1)
// G1 Collection
Disposer kalıbı, nesnelerin özel alanlarını temizlemelerini istemek için öngörülebilir bir yol ayarlamanıza yardımcı olur. Örneğin:
public class MyClass : IDisposable
{
private MyNestedType _nested;
// A finalizer is only needed IF YOU CONTROL UNMANAGED RESOURCES
// ~MyClass() { }
public void Dispose()
{
_nested = null;
}
}