2016-04-03 16 views
1

Her kare denen bir güncelleştirme döngüsü olan bir simülasyon yazıyorum. Güncelleme işlevinde, güncellenmesi gereken milyonlarca nesne var, dolayısıyla böyle görünüyor.C# çöp toplama nasıl azaltılabilir

public void Update(float deltaTime) 
{ 
    Time += deltaTime; 
    foreach (SimulationObject obj in objects.ToArray()) 
     obj.Update(deltaTime); 
} 

where objects is 
List<SimulationObject> objects = new List<SimulationObject>(); 
and is populated at program initialization time. 

Muhtemelen objects.ToArray() her çerçeve daha sonra kopya çöp toplama işlemine alır bu büyük listenin bir kopyasını yapar görebilirsiniz. Bu benim için büyük performans sorununa neden oluyor. Yaklaşık 2 dakika süren bir işlem için toplanan çöp yaklaşık 2G'ye ulaşıyor. Bu nesnelerin listesi bazı üçüncü taraf kitaplığı tarafından arka planda eşzamansız olarak değiştirildiğinden, ToArray() öğesini kaldıramıyorum.

Çöp toplama işlemini azaltmanın iyi bir yolu var mı, yoksa kopyalanan alanın kopyalanmasını veya yeniden kullanılmasını önlemek mi istiyorsunuz?

C# için yeni ve yanıt aramayı denedim, ancak mümkün değildi. Bu bir çoğaltılan gönderiyse özür dilerim. o zaman ve bellek sadece kaybıdır,

+2

Bilginize .ToArray() koleksiyonunun bir kopyasını oluşturur, 783a052330e7d48d – Eminem

+0

Lütfen şu adresteki cevaba bakınız: [Kısa bir süre çöp toplama işlemini önleme] (http://stackoverflow.com/questions/6005865/prevent-net-garbage-collection-for-short-period-of-time) – Eminem

+1

@Eminem - SimulationObject öğesinin bir "struct" (başvuru tipi) değil, "struct" (değer) olduğunu varsayar. – Corak

cevap

-1

ToArray() çağırmak için hiçbir sebep yoktur, bu yüzden sadece

public void Update(float deltaTime) 
{ 
    Time += deltaTime; 
    foreach (SimulationObject obj in objects) 
     obj.Update(deltaTime); 
} 
+2

Bu bir [InvalidOperationException] (https://msdn.microsoft.com/library/system.invalidoperationexception.aspx) - "koleksiyon değiştirildi" - eğer başka bir iş parçacığı üzerinde döngü yaparken koleksiyonu değiştirirse, OP'nin bir olasılık olduğunu söyledi. – Corak

3

ToArray() burada gerçekten gerekli değildir kullanabilirsiniz. for döngüsünü kullanın. Ben kasten Update()ArgumentOutOfRangeException atarsa ​​döngü kesintiye uğramasını engellemek amacıyla

for (int i = 0; i < objects.Count; i++) 
{ 
    SimulationObject obj = null; 
    try 
    { 
     obj = objects[i]; 
    } 
    catch (ArgumentOutOfRangeException) 
    { 
     // something was removed from the collection 
     // we reached the end of the list 
     break; 
    } 

    obj.Update(deltaTime) 
} 

Bu kod obj = objects[i] böler ve obj.Update(deltaTime) gibi bir başlangıç ​​olacaktır.

iki gerçeklerin farkında olun

: bunların ekleme tasarımı ile asenkron olarak onlar, aslında bir sorun olmamalı objects toplama eklendikten sonra

  • bazı nesneler ilk yineleme atlayacak.
  • Bazı nesneler, objects listesinden silindikten hemen sonra güncellenir (doğal olarak, aynı anda silme işlemi ile, ancak sonuç, "sonra" gibi görünme eğilimindedir). Simülasyona bağlı olarak bu durum arzu edilmeyebilir ve muhtemelen bazı özel işlemlere ihtiyaç duyacaktır.
+1

Bu aslında bu istisnayı (belki farklı bir istisna yakalarken) atlatır. Bu muhtemelen iş yapar. – Corak

+0

Kötülüklerimden kötüler. OP'nin ilk etapta güvenli diş koleksiyonları kullanması ya da iki liste tutması daha iyi olur diye düşünüyorum. – MickyD

+0

Tersine döngü yaparsanız, bir istisna atma olasılığı önemli ölçüde azalır. – egrunin

-1

Birinin işaret ettiği gibi, yalnızca varolan listenizin kopyasını oluşturacağından toArray() yöntemini kullanmanız gerekmez.

Doğru anlıyorsanız, listeniz arka planda üçüncü taraf lib tarafından değiştirildiğinden bunu yapıyorsunuz demektir.

Bu durumda Parallel.ForEach döngüsünü güvenle kullanabileceğinizi düşünüyorum, çünkü listenin kendisini değiştirmiyorsunuz, sadece listedeki öğeler. Koleksiyondaki nesneler http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs kopyalanmaz olsa

 Float Time; // some value 
     Float deltaTime; // some value 
     Parallel.ForEach(objects, currObject => 
      { 
       // do stuff 
      Interlocked.increment(ref Time,deltaTime); 
      currObject.Update(Time) 
      } 
İlgili konular