【发布时间】:2013-07-23 06:13:57
【问题描述】:
我一直在为使用 MailboxProcessor 的 F# 项目修复我的 TFS 测试运行。问题是我从 TFS 测试运行器收到的以下警告:
System.AppDomainUnloadedException:试图访问已卸载的 AppDomain。如果测试启动了一个线程但没有停止它,就会发生这种情况。确保测试启动的所有线程在完成之前都已停止。
我猜这个问题是由 MailboxProcessor 引起的。下面的 sn-p 演示了这个问题(我从 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
我希望输出行显示weakTarget 已死。但它活着。 我认为这表明存在一些内存泄漏。问题是我做错了什么? 而第二个问题是GC问题是否与TFS test runner问题有关。
【问题讨论】:
-
我会说最初的错误可能是由于邮箱处理器可能会启动额外的线程,这些线程在邮箱处理器被释放后仍然存在。这是一种完全自然的性能优化。
-
同意。问题是“我如何杀死邮箱处理器的所有优点”?
-
我运行了一个创建新
TestDisposable的无限循环,对垃圾回收是否真的发生了简单的测试。经过 500k 次迭代后,我发现内存使用量没有增加。我建议你的GC函数没有按照你的想法做。 -
我再次同意。虽然,我在 C# 中成功地使用了这个构造(假设构建的单元测试项目没有优化)来测试内存泄漏,它源于被遗忘的事件处理程序,应该被取消注册。所以,这里的 F# 和 C# 之间存在一些差异。
标签: asynchronous memory-leaks f# idisposable mailboxprocessor