【发布时间】:2012-01-29 02:46:18
【问题描述】:
我有以下方法(在棱镜的 RegionAdapter 中)。
protected override void Adapt(IRegion region, DocumentPane regionTarget)
{
region.Views.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e)
{
OnViewsCollectionChanged(sender, e, region, regionTarget);
};
}
我的问题是通过这种方式订阅事件,我有内存泄漏。但是 region 和 regionTarget 参数是 Adapt 的局部变量。
我尝试查找此内容以查看是否有人以不同方式处理该场景,但 MSDN 和 MVP 都使用这种泄漏方法...
我应该如何处理它以便我以后可以取消订阅该事件?
编辑:
上面的代码只是一个例子,我认为清楚地说明了问题。
实际泄漏内存的代码如下:
private void OnViewsCollectionChanged(object sender,
NotifyCollectionChangedEventArgs e, IRegion region,
DocumentPane regionTarget)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
//Add content panes for each associated view.
foreach (object item in e.NewItems)
{
UIElement view = item as UIElement;
if (view != null)
{
DockableContent newContentPane = new DockableContent();
newContentPane.IsCloseable = true;
newContentPane.HideOnClose = false;
ScrollViewer sViewer = new ScrollViewer()
{
Content = item,
HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
VerticalScrollBarVisibility = ScrollBarVisibility.Auto
};
newContentPane.Content = sViewer;
//When contentPane is closed remove the associated region
// (MEMORY LEAK)
newContentPane.Closed += (contentPaneSender, args) =>
{
DockableContent docker =
contentPaneSender as DockableContent;
ScrollViewer scroller = docker.Content as ScrollViewer;
region.Remove(scroller.Content);
IDisposable dispView = scroller.Content as IDisposable;
if (dispView != null) dispView.Dispose();
scroller.Content = null;
};
regionTarget.Items.Add(newContentPane);
newContentPane.Activate();
}
}
}
}
谢谢,
巴布。
【问题讨论】:
-
为什么你认为它会泄漏内存?只要
Views实例仍然被引用,包含Adapt方法的类的实例就会留在内存中。当region被收集时,你的Adapter也会被收集。您的region是对静态实例的引用吗? -
如果您将
OnViewsCollectionChanged方法设为静态(如果可能),它会阻止Adapter被引用。 -
实际上,这是重现问题的最微小的一点。最常用的区域注入了无限量的视图。我将更新问题以显示导致严重内存泄漏的原因,但我想您理解不是取消订阅 = 内存泄漏。
-
@Steven 所以如果我做对了,如果我把 Closed 事件处理中使用的匿名方法的内容放在一个常规的静态方法中,我确保不会有内存泄漏?跨度>
-
没错。 C# 编译器将生成一个带有
region和regionTarget作为公共字段的匿名类型,当OnViewsCollectionChanged是实例方法时,该匿名类型还将包含对持有OnViewsCollectionChanged的实例的引用。当OnViewsCollectionChanged为静态时,该匿名类型将不包含对该实例的引用,因此该实例将不会保持活动状态。您可以使用 Reflector 确认这一点。
标签: c# memory-leaks delegates