MailboxProcessor.Dispose не делает объект GC коллекционным
Я застрял с исправлением моих тестов TFS, запускаемых для проекта F#, который использует MailboxProcessor. Проблема заключается в следующем предупреждении, которое я получаю от тестировщика TFS:
System.AppDomainUnloadedException: попытка получить доступ к незагруженному домену приложения. Это может произойти, если тест (ы) запустил поток, но не остановил его. Убедитесь, что все потоки, запущенные тестом (-ами), остановлены до завершения.
Я думаю, что проблема вызвана MailboxProcessor. Следующий фрагмент демонстрирует проблему (я запускаю его из fsi):
open System.Threading
open System
type TestDisposable () =
let cts = new CancellationTokenSource ()
let processMessage (inbox:MailboxProcessor<int>) =
let rec loop n =
async {
let! msg = inbox.Receive ()
return! loop (n+msg)
}
loop 0
let agent = MailboxProcessor<int>.Start (processMessage, cts.Token)
interface IDisposable with
member this.Dispose () =
(agent :> IDisposable).Dispose ()
cts.Cancel ()
cts.Dispose ()
printfn "TestDisposable.Dispose called"
do
let weakTarget =
use target = new TestDisposable ()
new WeakReference (target)
GC.Collect()
GC.WaitForPendingFinalizers()
GC.WaitForFullGCComplete() |> ignore
GC.Collect()
printfn "WeakTarget is alive: %b" weakTarget.IsAlive
Я ожидаю, что выходная строка скажет, что уязвимый объект мертв. Но он жив. Я думаю, что это указывает на некоторую утечку памяти. Вопрос в том, что я делаю не так? И второй вопрос - связана ли проблема GC с проблемой бегуна тестов TFS.
1 ответ
Код примера, который вы разместили, будет содержать ссылку на target
вероятно, потому что у вас есть привязка верхнего уровня к нему (use target = new TestDisposable()
).
Если вы измените код на что-то вроде приведенного ниже кода, вы увидите, что weakTarget
мертв, потому что ссылка на target
только местный test()
функция.
do
let test() =
use target = new TestDisposable()
new WeakReference(target)
let weakTarget = test()
GC.Collect()
GC.WaitForPendingFinalizers()
GC.WaitForFullGCComplete() |> ignore
GC.Collect()
printfn "WeakTarget is alive: %b" weakTarget.IsA
Я не знаю, исправит ли это вашу первоначальную проблему, поскольку это довольно специфично для того, как вы написали пример кода.