Bar*_*aal 12 .net wpf garbage-collection memory-management
更新:我在另一台安装得更干净的机器上尝试了这个.我无法在那台机器上重现这一点.如果我发现有什么令人讨厌的(VSStudio)组件导致这种情况,我会告诉你.
我从后面的代码创建了一些UIElements,并期待垃圾收集来清理东西.但是,在我预期的时候,对象不会被自由编辑.我期待他们在RemoveAt(0)被释放,但他们只在程序结束时被释放.
从Canvas的Children集合中删除时,如何释放对象?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
MouseDown="Window_MouseDown">
<Grid>
<Canvas x:Name="main" />
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)
背后的代码是:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
GC.Collect(); // This should pick up the control removed at a previous MouseDown
GC.WaitForPendingFinalizers(); // Doesn't help either
if (main.Children.Count == 0)
main.Children.Add(new MyControl() { Background = Brushes.Yellow, Width = 100, Height = 50 });
else
main.Children.RemoveAt(0);
}
}
public class MyControl : UserControl
{
~MyControl()
{
Debug.WriteLine("Goodbye");
}
}
Run Code Online (Sandbox Code Playgroud)
更改
public class MyControl : UserControl
至
public class MyControl : ContentControl
并且它会说再见(在第二次移除控件之后.)我还通过使用验证了内存不泄漏
Debug.WriteLine("mem: " + GC.GetTotalMemory(true).ToString());
另外,看到这个:
您通过清除grid.Children删除TestControl,但它不能立即符合垃圾回收的条件.它上面的几个异步操作正在等待,并且在这些操作完成之前它不能是GC(这些包括在渲染引擎中引发Unloaded事件和一些清理代码).
我验证了如果等到这些操作完成(比如通过在ContextIdle优先级上安排Dispatcher操作),TestControl就有资格获得GC,而不管TextBlock上是否存在绑定.
UserControl必须具有不能快速清理的内部事件,或者它可能是VS2010 RC的错误.我通过connect报告这个,但是现在切换到ContentControl.
由于您正在使用UserControl,我假设您还必须切换到使用Generic.xaml模板.转换并不太难(对于大多数事情而言,这是一个更好的解决方案.)
您可能会对此感兴趣。我最近发现 x:Name 标记扩展在以字符串名称为键的字典中存储了对父控件中 UIElement 的引用。
当您从其父级中移除 UIElement 时,字典会保留对该控件的引用。
这里有一篇博客文章/视频调试内存泄漏:WPF x:Name Memory Leak
解决方法是不使用 x:Name 或确保通过 x:Name 保持活动的控件被清除,以免在收集可视化树的一部分之前消耗太多内存。
更新:您使用NameScope取消注册命名类
this.grid.Children.Remove(child); // Remove the child from visual tree
NameScope.GetNameScope(this).UnregisterName("child"); // remove the keyed name
this.child = null; // null the field
// Finally it is free to be collected!
Run Code Online (Sandbox Code Playgroud)
C# 中的对象不会在不再使用后立即自动“释放”。
相反,当您从 Control 中删除该对象时,假设您没有对该 UI 元素的其他引用,那么该对象此时就可以进行垃圾回收。
一旦对象被“无根”(不存在直接或间接来自应用程序中任何使用的对象的引用),它就符合收集条件。垃圾收集器最终将清理您的对象,但何时发生这种情况不是您(通常)可以控制的。
只要相信它最终会被清理干净。这就是 C#(以及一般的 .NET)的美妙之处 - 管理和烦恼都为您处理。
编辑:经过一些测试,窗口似乎保留了对 UIelement 的引用,直到下一个布局通过。您可以通过添加以下调用来强制执行此操作:
this.UpdateLayout();
Run Code Online (Sandbox Code Playgroud)
从画布子元素中删除元素后。这将导致对象可用于 GC。
归档时间: |
|
查看次数: |
23700 次 |
最近记录: |