Dlaczego zadanie LongRunning (TPL) z JpegBitmapDecoder wyczerpuje zasoby?

Mamy zarządzaną aplikację .Net / C #, która tworzy zadania TPL w celu kodowania metadanych JPEG na obrazach JPEG. Każde zadanie jest zbudowane za pomocą opcji TaskCreationOptions.LongRunning, np.

Task task = new Task( () => TaskProc(), cancelToken, TaskCreationOptions.LongRunning );

TaskProc () wykorzystuje klasy JpegBitmapDecoder i JpegBitmapEncoder do dodawania metadanych JPEG i zapisywania nowych obrazów na dysku. Zezwalamy na aktywowanie maksymalnie 2 takich zadań jednocześnie, a proces ten powinien być kontynuowany w nieskończoność.

Po pewnym czasie wykonywania wyżej wymienionych otrzymujemyZa mało pamięci do przetworzenia tego polecenia wyjątek podczas próby utworzenia instancji klasy JpegBitmapDecoder:

System.ComponentModel.Win32Exception (0x80004005): Brak dostępnej pamięci do przetworzenia tego polecenia w MS.Win32.UnsafeNativeMethods.RegisterClassEx (WNDCLASSEX_D wc_d)
w MS.Win32.HwndWrapper..ctor (klasa Int32, styl Int32, Int32 exStyle, Int3 2 x, Int32 y, szerokość Int32, wysokość Int32, nazwa String, IntPtr rodzic, HwndWrapperHoo k [] haki) w System.Windows.Threading .Dispatcher..ctor () w System.Windows.Threading.Dispatcher.get_CurrentDispatcher () w System.Windows.Media.Imaging.BitmapDecoder..ctor (Stream bitmapStream, BitmapC reateOptions createOptions, BitmapCacheOption cacheOption, Guid expectedClsId) w System.Windows .Media.Imaging.JpegBitmapDecoder..ctor (Stream bitmapStream, Bit mapCreateOptions createOptions, BitmapCacheOption cacheOption)

Wystąpił błądtylko kiedy wykorzystaliśmy JpegBitmapDecoder do dodania metadanych. Innymi słowy, jeśli zadanie po prostu kodowałoby i zapisywało obraz bitmapowy do pliku, nie powstałyby żadne problemy. Nic oczywistego nie zostało ujawnione podczas korzystania z Process Explorer, Process Monitor lub innych narzędzi diagnostycznych. W ogóle nie zaobserwowano żadnych wycieków wątków, pamięci ani obsługi. Gdy wystąpi taki błąd, nie można uruchamiać żadnych nowych aplikacji, np. Notatnika, słowa itp. Gdy nasza aplikacja zostanie zakończona, wszystko wraca do normy.

Opcja tworzenia zadania LongRunning jest zdefiniowana w MSDN jakoOkreśla, że ​​zadaniem będzie długotrwała, gruboziarnista operacja. Zawiera wskazówkę dla TaskScheduler, że nadsubskrypcja może być uzasadniona. Oznacza to, że wątek wybrany do uruchomienia zadania może nie pochodzić z Puli wątków, tj. Zostanie utworzony na potrzeby zadania. Inne opcje tworzenia zadania spowodują, że wątek ThreadPool zostanie wybrany do zadania.

Po pewnym czasie analizowania i testowania zmieniliśmy opcję tworzenia zadań na inne niżLongRunning, np.PreferFairness. W ogóle nie wprowadzono żadnych innych zmian w kodzie. To „rozwiązało” problem, tj. Nie skończyły się błędy pamięci.

Jesteśmy zdziwieni faktycznym powodem, dla którego LongRunning jest sprawcą. Oto niektóre z naszych pytań na ten temat:

Dlaczego fakt, że wątki wybrane do wykonania zadania pochodzą z Puli wątków, czy nie? Jeśli wątek zostanie zakończony, czy jego zasoby nie powinny być odzyskiwane przez GC i zwracane z powrotem do systemu operacyjnego, niezależnie od jego pochodzenia?

Co jest takiego wyjątkowego w połączeniu zadania LongRunning i JpegBitmapDecoder, które powoduje błąd?

questionAnswers(2)

yourAnswerToTheQuestion