2012-12-26 13 views
7

mam wyciek pamięci podczas korzystania ConcurrentQueue:przeciek pamięci z ConcurrentQueue

requestObject request = xxx; 

Item obj= new Item(); 
obj.MessageReceived += obj_MessageReceived; 
obj.Exited += obj_Exited; 

request.Key = obj.Key; 

obj.AddRequest(request); 

_queue.TryAdd(obj.Key, obj); 

W "Exited" zwrotnego, i dysponowania zasobu:

void LiveSphere_Exited(string key) 
{ 
    Item instance; 

    _queue.TryRemove(key, out instance); 

    Task.Factory.StartNew(() => 
    { 
     var wait = new SpinWait(); 
     while (instance.MessageCount > 0) 
     { 
      wait.SpinOnce(); 
     } 
    }) 
    .ContinueWith((t) => 
    { 
     if (instance != null) 
     { 
      //Cleanup resources 
      instance.MessageReceived -= obj_MessageReceived; 
      instance.Exited -= obj_Exited; 
      instance.Dispose(); 
      instance = null; 
     } 
    }); 
} 

Kiedy profil kodu, mam jeszcze obiekt odniesienia "obiekt", ale nie wiem, gdzie mogę go wyrzucić ..., Wywołana metoda jest wyzwalana, a funkcja _queue usunęła obiekt "Obiekt" z kolejki.

Gdy czytam dokumentację, współbieżna kopia kopiuje odwołanie do kolejki.

Czy możesz mi pomóc dowiedzieć się, gdzie jest wyciek pamięci?

+5

Nie wiesz, gdzie znajduje się wyciek pamięci. Wystąpił przeciek pamięci w wersji "ConcurrentQueue" .NET 4.0, ale został naprawiony na 4.5. Możesz rozważyć zapoznanie się z 'BlockingCollection', który jest znacznie ładniejszym opakowaniem wokół zbieżnych kolekcji. Domyślne zachowanie używało 'ConcurrentQueue' wewnętrznie. –

+0

Wahałbym się, że zadzwoniłbym do '.A4 4' ConcurrentQueue' - głównie działo się to tylko wtedy, gdy nie korzystałeś z niego zbyt wiele (nie ustawiłoby to danych na 'null', dopóki nie pojawiło się kilka elementów) - w takim przypadku , jaki jest sens "ConcurrentQueue"? –

+0

Dziękuję Jim, ale już jestem w .NET 4.5 i potrzebuję kolejki FIFO, czy kolekcja blokująca to FIFO? – dnx

Odpowiedz

6

W przeciwieństwie do standardowej kolejki .NET, wywołanie opcji Dequeue() nie usuwa odwołania do obiektu z kolekcji. Chociaż to zachowanie zmieniło się z wersji 4.0 na wersję 4.5 (przeczytałem to, ale nie przetestowałem), to nie jest błąd, ale świadoma decyzja dotycząca projektu podjęta przez zespół konstruktorów w ramach projektowania bezpiecznego wątku , kolekcję przeliczalną.

This article ma więcej informacji, w tym obejście, za pomocą StrongBox do zawijania obiektów, które trafiają do ConcurrentQueue. To powinno być odpowiednie obejście, dopóki nie przeniesiesz się do frameworka 4.5.

+2

Nazwałbym to "świadomym błędem projektu", biorąc pod uwagę jego wynik. – hypersw

+0

Próbowałem tego podejścia StrongBox, ale tylko opóźnia problem. pamięć wciąż rośnie do około 1,7 GIG, a następnie aplikacja ma problemy z opóźnieniami i awarie. – user2520306

1

Zajrzałem do realizacji kolejki równoczesnej. Istnieją przypadki, gdy kolejka będzie przechowywać odniesienia do obiektu po wywołaniu Dequeue().

Jednoczesna kolejka korzysta z segmentów do przechowywania danych. Nie jest to częścią metody TryRemove segmentu:

// If there is no other thread taking snapshot (GetEnumerator(), ToList(), etc), reset the deleted entry to null. 
// It is ok if after this conditional check m_numSnapshotTakers becomes > 0, because new snapshots won't include 
// the deleted entry at m_array[lowLocal]. 
if (m_source.m_numSnapshotTakers <= 0) 
{ 
    m_array[lowLocal] = default(T); //release the reference to the object. 
} 

Więc gdy masz inny wątek, który wylicza kolejkę w tym samym czasie można rozkolejkowania an object odniesienia do obiektu nie zostanie ustawiona na null.

Powiązane problemy