我试图确保使用 Rx 的类实例不会泄漏。我已将问题简化为最基本的问题,看起来 Window 函数是问题的关键。
考虑以下因素:
<!-- language: c# -->
using System;
using System.Reactive.Linq;
class Program
{
static void Main(string[] args)
{
var foo = new Foo();
Console.WriteLine("Press any key...");
Console.ReadKey(true);
foo = null;
GC.Collect();
Console.WriteLine("Press any key...");
Console.ReadKey(true);
}
}
public class Foo
{
private event EventHandler MyEvent;
public Foo()
{
var subs = Observable.FromEventPattern(
e => MyEvent += e, e => MyEvent -= e);
// (1) foo is never GC'd
subs.Window(TimeSpan.FromSeconds(1)).Subscribe();
// (2) foo is GC'd
//subs.Window(TimeSpan.FromSeconds(1));
// (3) foo is GC'd
// subs.Window(1);
}
~Foo()
{
Console.WriteLine("Bye!");
}
}
当我使用 TimeSpan 打开选择器应用 Window 函数并订阅它时,(1) foo 永远不会被 GC 回收。
如果我不订阅 (2),或者我使用不同的打开选择器 (3),那么它就是。
此外,如果我使用冷可观察量作为源,那么 foo 无论如何都会被 GC 处理。
为什么带有 TimeSpan 的 Window 函数很特殊,以及如何确保 foo 在使用它时会被 GC 回收?
最佳答案
这对我来说看起来是正确的。
您缺少对 IDisposable 字段的订阅分配。您不会处置订阅,也不会调用 GC.WaitForPendingFinalizers();
您可以使用以下方法修复测试:
public class Foo : IDisposable
{
private event EventHandler MyEvent;
private readonly IDisposable _subscription;
public Foo()
{
var subs = Observable.FromEventPattern(
e => MyEvent += e,
e => MyEvent -= e);
// (1) foo is never GC'd
//subs.Window(TimeSpan.FromSeconds(1)).Subscribe();
_subscription = subs.Window(TimeSpan.FromSeconds(1)).Subscribe();
// (2) foo is GC'd
//subs.Window(TimeSpan.FromSeconds(1));
// (3) foo is GC'd
// subs.Window(1);
}
public void Dispose()
{
_subscription.Dispose();
}
//TODO: Implement Dispose pattern properly
~Foo()
{
_subscription.Dispose();
Console.WriteLine("Bye!");
}
}
测试现在可以变成
//foo = null; //This will just change our reference, the object sill lives and has stuff happening with timers etc..
foo.Dispose(); //Dispose instead of killing reference
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
我希望这会有所帮助。另请查看Lifetime Management发表在我的 Rx 博客系列简介上。
更新:我的在线图书 IntroToRx.com取代博客系列。这里最相关的似乎是 Lifetime management章。
关于c# - 在可观察事件上使用带有 TimeSpan 的 Rx Window 操作可防止垃圾收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9260321/