2009-11-06 21 views
11

Yazdığım küçük hobi oyunu için basit bir Kaynak Yöneticisi yazmaya çalışıyorum. Bu kaynak yöneticisinin yapması gereken görevlerden biri, kullanılmayan kaynakları boşaltmaktır. Ben iki yolla bunu düşünebilirsiniz:C# - Nesne başvuru sayısı al

  • bir nesne artık, bu artık kullanıyor belirtmek için Kaynak Yöneticisi bir yöntem çağırmalıdır kaynağına başvuru gerektiriyorsa; veya

  • bir nesne artık kaynağına başvuru gerektirir

    , sadece null değerine ayarlar. Daha sonra Kaynak Yöneticisi'nden kullanılmayan kaynakları boşaltması istendiğinde, her bir kaynak için referans sayımı (yansıma aracılığıyla) alır. başvuru sayısı birse (Kaynak Yöneticisi kaynağına bir başvuru yapar), kaynağı boşaltın.

C# 'daki ikinci çözümü elde etmenin bir yolu var mı? Teşekkürler.

+0

Kaynak yöneticiniz garbace toplayıcısının bunu yapmaz mı? – CannibalSmith

+1

@CannibalSmith - tipik olarak, birden çok kod bitinin kaynağı yeniden kullanmasına izin verir (temel olarak, bir önbellek) –

+0

Görüntüleri yüklemek için, bir seferde yalnızca bir resmin yüklendiğinden emin olmak için (yalnızca kaç tane sorun olursa olsun) bir versiyon hafızada olabilir). –

cevap

11

Kaynak yöneticisinden WeakReference'u kullanabileceğinizi görüyorsunuz. GC dinlenme yapacak. Küçük bir döküm yapman gerekecek, ama basit olacak ve işe yarayacak.

class Manager { 
    Dictionary<string, WeakReference> refs = 
     new Dictionary<string, WeakReference>(); 
    public object this[string key] { 
     get { 
      WeakReference wr; 
      if (refs.TryGetValue(key, out wr)) { 
       if(wr.IsAlive) return wr.Target; 
       refs.Remove(key); 
      } 
      return null; 
     } 
     set { 
      refs[key] = new WeakReference(value); 
     } 
    } 
} 
static void Main() { 
    Manager mgr = new Manager(); 
    var obj = new byte[1024]; 
    mgr["abc"] = obj; 

    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
    Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj") 

    obj = null; 
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); 
    Console.WriteLine(mgr["abc"] != null); // false (no remaining refs) 
} 
+0

Bunu yaparım :) Bir şey olsa da: Yanılıyor olabilirim, ama sözlükten uygun bir başvuru almanız ve geri göndermeden önce boş olup olmadığını kontrol etmeniz gerekebilir. "If (wr.IsAlive) return wr.Target" yaparsanız, asla güçlü bir ref almayacaksınız, bu yüzden IsAlive doğru olabilir, ancak değeri döndürdüğünüzde, wr.Target toplanmış olabilir. Burada alternatif bir kod örneği var: http://msdn.microsoft.com/en-us/library/system.weakreference.aspx –

+1

'object' toplanmayı engelleyecek kadar güçlüdür; ya 'null' ya da güçlü olacak. Arayan bunu bir * yazarak * referans yapmak için çevirmek zorunda kalacaktı, ama bu farklı bir sorundur ... –

+0

.NET 4.5, WeakReference'ın genel bir sürümüne sahiptir, bunu kontrol edin http://www.philosophicalgeek.com/2014/08/14/tercih-weakreferencet-to-WeakReference / – Logerfo

2

NET'te bir kaynak yöneticimiz var, çöp toplayıcısını çağırdık. Bu yüzden çok verimli bir yaklaşım referansları sıfırlamak ve hiçbir şey yapmamaktır.

Daha doğrudan bir yanıt: Hayır, referanslarını bir nesneye almak için bir yol yoktur.

WeakReference class'u incelemek veya bir Caching sistemi kullanmak isteyebilirsiniz.

1

Kaynak yöneticinizin kaynaklarınıza WeakReference s bağlantısını kullandığından emin olun. Bu şekilde, başka kimsenin kaynaklara başvurmadığı durumlarda, çöp toplama için uygun olacaktır.

0

Daha önce zaten GC tarafından yapılır ulaşmaya çalıştıkları ve ince bir WeakReference kullanılarak ayarlanabilir başka hangi kullanıcılar tarafından söylendi.

Bu, .NET, java, vb. Gibi yönetilen ortamlarda sorun olmadığını gösterir.

Düşük düzeyli çerçeve mimarisi sizi bellek yönetiminden ayırdığı için, hala bu tür bir işleve ihtiyacınız varsa, kod mimarinizi gözden geçirmenizi öneririm, çünkü bu bir çeşit yaptığınız anlamına gelir bellek yönetiminde kötü alıştırma

28

Çift şeyler. İlk önce, nesneler referans sayılmaz; Referans sayma şemaları dairesel referans problemine sahiptir, bu sayede iki nesne birbirine atıfta bulunur, ancak başka türlü erişilemez ve dolayısıyla sızıntıya neden olur. .NET, sayım kullanmayan bir işaretleme ve tarama yaklaşımı kullanır.

İkincisi, zayıf bir referans kullanma önerisi korkunç olmamakla birlikte, aynı zamanda bir slam dunk değildir. Performans nedeniyle bir önbellek oluşturuyorsunuz.(Uygulamanızın performans özelliklerine ilişkin dikkatli, deneysel ve gerçekçi araştırmalarınızın, kabul edilebilir bir performans elde etmek için bir önbellekleme stratejisinin gerekli olduğunu ikna edici bir şekilde gösterdiğini varsayardım, eğer durum böyle değilse, bu kararları erken yapıyorsunuz.) Her Önbelleğin kaynaklarını ne zaman yayınladığı konusunda bir POLİTİKASI olması gerekir, aksi halde bir bellek sızıntısı olur.

GC politikasının ve politikanızın eşdeğer ilkeler olduğunu nereden biliyorsunuz? GC, spesifik performans ihtiyaçlarınız göz önüne alınarak tasarlanmamıştı. Yani, aklınızdaki herhangi bir performans hedefine ulaşmamak için gerçekten çöp olan kaynakları serbest bırakmak üzere tasarlandı. Kararın GC'ye devredilmesiyle, önbellek politikanızı performans ihtiyaçlarınıza göre ayarlama becerilerinizden vazgeçersiniz.