WPF内存泄漏

我有一个简单的wpf应用程序。 在主窗口中,我有堆栈面板和2个按钮。 第一个按钮添加了100个用户控件(没有任何数据绑定,事件,位图),第二个按钮从面板中删除所有这些控件并调用GC.Collect()。 并且存在一些问题:1。在我第一次单击“删除”按钮后,并非所有内存都释放,我必须单击几次以释放更多内存。 2. 5-10分钟内存释放后,但不会有几兆字节。

例如,在我的应用程序启动后,当我添加500个控件时需要~22mb – 在我第一次点击“删除”按钮后~~~60mb~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ,我不明白这一点,我是WPF的新手,也许我想念一些我想立即释放内存的东西。

             

 namespace WpfApplication10 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void button1_Click(object sender, RoutedEventArgs e) { int N = 100; //var r = new ActivityStatisticItem("111", "222", DateTime.Now, "333", 1); for (int i = 0; i < N; i++) { activityStackPanel.Children.Add(new UserControl1()); } label1.Content = activityStackPanel.Children.Count; } private void button2_Click(object sender, RoutedEventArgs e) { activityStackPanel.Children.Clear(); label1.Content = activityStackPanel.Children.Count; GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); } } }          

在用户控制中我只有

  public UserControl1() { InitializeComponent(); } 

我想立即释放记忆。

别。 信任GC。

 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); 

别。 信任GC。

5-10分钟后释放内存

我不是说信任GC吗?


  • 垃圾收集模型将确保释放系统中不需要的托管内存(其中包括几乎所有控件内存)。 它使用一种优化算法,包括代,可用的可用内存,可能的CPU可用……因此GC.Collect()会干扰它。

  • GC.Collect()是异步的,因此没有立竿见影的效果。

  • 您需要注意的唯一资源是非托管资源,通常由Dispose Pattern处理。 否则不要乱用GC,它的工作做得很好。

 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); 

这是一种将非GCable对象过早地强制转换为Gen2的可靠方法,因此可以在更长的时间内增加内存占用,这是没有充分理由的。

正如Aliostad所说:不要!

将垃圾收集器单独留下并让它完成其工作。

你所描述的不是内存泄漏。 它是动态内存,在您认为它应该被释放的那一刻不会被释放。

你是垃圾收集器吗? 你不是。 担心什么时候收集垃圾不是你的工作。 如果这些对象实际上是垃圾 – 而且它们是 – 当你需要它时,内存就会存在。

在垃圾收集环境中, 立即释放内存并没有多大意义。

由于CLR JIT按需编码,因此第一次运行测试时,您不应该看到内存回退到最初的位置。 这是有道理的,因为已经遵循新的代码路径并且代码已被JIT。 那段代码需要驻留在内存中的某个地方吗?

因此,在第一次测试运行后,您应该无法收集到最初的内存占用量。 您的基线应该是运行测试一次后获得的内存使用量,而不是之前。 在第二次运行之后,我可以通过多个集合将内存恢复到基线。

另外,我建议您在发布模式下运行项目,不附加调试器。 使用附加的调试器运行程序不会显示真正的内存配置文件,因为它使用各种技巧来保持对象(例如, 收集对象仍在范围内 – GC.Collect )。

然而,这完全是一个有争议的问题,因为正如我上面所述,在GC环境中(在大多数情况下)回收内存并不是很有意义。

我会同意@Aliostad re GC。 我做得很好,但它不是一个神奇地清除你所有记忆的工具。

如果您有内存泄漏问题,最直接和最可靠的解决方案是使用分析器,它应该能够识别您是否有真正的泄漏以及它在哪里。 我使用过红门的ant,但其他人可能有更好的建议。

以及遵循通常的指导方针,例如确保妥善处理东西。 调用GC并希望它能够正常工作不是正确代码评估的替代方案。

通过使用这个Dll Invoke,我们可以重新定位内存资源

 public class MemoryManagement { [DllImportAttribute("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize); public static void FlushMemory() { GC.Collect(); GC.WaitForPendingFinalizers(); if (Environment.OSVersion.Platform == PlatformID.Win32NT) { SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1); } }