use*_*248 4 c# garbage-collection memory-leaks
假设我有一个 C# 类,如下所示:
public class MyClass {
public SomeObject TheObject { get; }
public MyClass() {
TheObject = new SomeObject();
TheObject.MyEvent += MyEventHandler;
}
private void MyEventHandler() {
// some code
}
}
Run Code Online (Sandbox Code Playgroud)
该类创建一个名为 TheObject 的 SomeObject 类型的内部对象,并向该对象上的事件添加一个事件处理程序。
由于 TheObject 是一个公共属性,这意味着任何其他代码段都可以维护指向该对象的指针;反过来,这将使 MyClass 类型的对象保持活动状态,因为 TheObject 有一个以事件处理程序形式指向 MyClass 的指针。
因此,我认为保持此代码不受此事件影响的唯一方法是向 MyClass 添加终结器:
public ~MyClass() {
TheObject?.MyEvent -= MyEventHandler;
}
Run Code Online (Sandbox Code Playgroud)
这太糟糕了,因为终结器会将 MyClass 类型的对象提升到下一代 GC,但我是否正确地认为这是避免这种潜在内存泄漏的唯一方法?
您的解决方案实际上不会解决问题,因为在可以收集对象之前不会调用终结器本身,并且正如您正确识别的那样,TheObject将通过事件处理程序使对象保持活动状态。
有两个潜在的修复:
MyClass实现IDisposable和注销事件处理程序Dispose。C# 具有using帮助使用类的语法一个简单的实现是:
public interface ISubscription
{
bool IsAlive { get; }
void Fire();
}
public class Subscrition<T> : ISubscription
where T: class
{
public Subscrition(T target, Action<T> fire)
{
this.Target = new WeakReference<T>(target);
this.FireHandler = fire;
}
public WeakReference<T> Target { get; }
public Action<T> FireHandler { get; }
public bool IsAlive => this.Target.TryGetTarget(out var t);
public void Fire()
{
if (this.Target.TryGetTarget(out var target))
{
this.FireHandler(target);
}
}
}
public class WeakEvent
{
List<ISubscription> weakHandlers = new List<ISubscription>();
public void Register<T>(T target, Action<T> fire)
where T:class
{
this.Prune();
this.weakHandlers.Add(new Subscrition<T>(target, fire));
}
public void Unregister(ISubscription subscription)
{
this.Prune();
this.weakHandlers.Remove(subscription);
}
// Prune any dead handlers.
public void Prune()
{
this.weakHandlers.RemoveAll(_ => !_.IsAlive);
}
public void Fire()
{
this.Prune();
this.weakHandlers.ForEach(_ => _.Fire());
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
public class SomeObject
{
public WeakEvent WeakMyEvent = new WeakEvent();
}
public class MyClass
{
public SomeObject TheObject { get; }
public MyClass()
{
TheObject = new SomeObject();
TheObject.WeakMyEvent.Register(this, t => t.MyEventHandler());
}
private void MyEventHandler()
{
// some code
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以查看这篇文章以获得更复杂的实现
| 归档时间: |
|
| 查看次数: |
1065 次 |
| 最近记录: |