在C#WPF内存泄漏(Memory Leak in C# WPF)

2019-10-21 08:43发布

我需要减少处置所有使用的对象后,在C#WPF内存泄漏。 但我不能使用下面的代码片段完全减少内存消耗。

这里是我的代码:

string str;
Uri uri;
private void Button_Click(object sender, RoutedEventArgs e) // "Load" Button
{
    if(img.Source!=null)
    Unload();    
    str = "F://Photos//Parthi//IMG_20141128_172826244.jpg";   // File Size: 0.643 MB            
    uri = new Uri(str);
    img.Source = new BitmapImage(uri);                         
}

private void Button_Click_1(object sender, RoutedEventArgs e) //"Unload Button"
{
    Unload();
}

private void Unload()
{
    Bitmap bmp = GetBitmap(img.Source as BitmapSource);
    bmp.Dispose();
    bmp = null;
    img.Source = null;           
    str = string.Empty;
    uri = null;
}
private Bitmap GetBitmap(BitmapSource source)
{
    Bitmap bmp = new Bitmap(source.PixelWidth, source.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    source.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
    bmp.UnlockBits(data);
    data = null;
    source = null;
    return bmp;
}

运行样品后,虽然在任务管理器检查它,下面的内存消耗读数已经产生,

之前“加载”按钮被点击:10.0 MB

经过“加载”按钮被点击:47.8 MB

后“卸载”按钮被点击:26.0 MB

卸载后,我需要密切减少内存10.0 MB。 所以,请帮我对此。

提前致谢。

Answer 1:

使用.NET平台没有对内存的控制,如果它工作在C / C ++的垃圾收集工作非常复杂的政策,你往下看内存到26,但10是正常的事实。 在.NET保留一个空间,充电更快的数据,并保证在主内存中的自由空间,而不必需要连续操作系统。

我已经注意到是完全正常的。 这是一个问题,在过去我个人一个过程中经受微软MVP

查看本: http://msdn.microsoft.com/en-us/library/ee787088%28v=vs.110%29.aspx

这: 在C#中强制垃圾收集最佳实践



Answer 2:

首先,不使用任务管理器来查看您的内存使用,因为它只是说明了Windows进程分配内存。 有很多更好的工具,在那里,甚至在性能监视器,其自带的Windows,会给你的应用程序的性能和任何内存泄漏更好的主意。 您可以通过运行启动perfmon.exe

在此示例应用程序,直到堆达到约85MB GC不会成为积极与收藏。 为什么我会希望它? 这不是一个大量的内存和它工作得很好的缓存解决方案,如果我决定再次使用相同的对象。

所以,我建议考虑看看该工具。 它给了什么事情的一个很好的概述,它是免费的。

其次重要的是,只是因为你叫.Dispose()来释放这些资源,并不意味着内存被释放的时候了。 你基本上使它符合垃圾收集,当GC得到它,它会照顾它。

用于WPF应用程序的默认垃圾收集行为是并行(<4.0)/背景(4.0 = <)工作站GC。 它运行在一个特殊的线程和大部分的时间试图同时运行的应用程序(我的大部分时间说的休息,因为过一段时间它会非常短暂暂停其他线程,以便它可以完成其清理)。 它不会等待,直到你的记忆,但在同一时间,它收集只有当它不极大地影响性能 - 排序均衡权衡。

另一个需要考虑的因素是,你有0.643 MB的JPEG文件,一旦你算BitmapImage ,这是一个有点......好吧,高于一切85,000 bytes被认为是一个大的对象,因此,它被放置到第2代,它包含大对象堆。 第2代垃圾收集是昂贵的,不经常做。 但是,如果你正在运行的.NET 4.5.1,我不知道,如果你是,你可能会迫使压实:

GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collection();

正如.Dipose()这是不会马上发生,因为它是一个昂贵的过程,它会需要更长的时间比第1代低于一毫秒的横扫。 而且说实话,你可能甚至不会从中获益,因为我怀疑,你将不得不与该应用程序的LOH一个高不成。 我刚才提到它让你意识到这个选项,如果你需要它。

那么,为什么我给你一个WPF应用程序(和为此事大多数的.NET应用程序)的默认行为GC一个简短的教训? 好了,了解GC的行为,并承认它的存在是很重要的。 不像C ++应用程序,在那里你给予大量的控制和自由的在你的内存分配,.NET应用程序利用GC。 权衡的是,当它是由GC释放的内存被释放。 甚至有可能是时候,它释放它过早,从你的角度来看,那就是当你将明确保留的对象通过调用活着GC.KeepAlive(..) 许多嵌入式系统中不使用一个GC的,如果你想在你的记忆非常精确的控制,我建议你也不会。

如果你想知道如何内存在.NET应用程序正在处理,我强烈建议在垃圾收集器的内部工作方式教育自己。 我已经告诉你的是默认的行为,一个令人难以置信的简单快照,有很多更给它。 有几个模式,提供不同的行为。



Answer 3:

尝试管理你的变量的使用。 你可以这样做:

private void Button_Click(object sender, RoutedEventArgs e) 
{
  img.Source = new BitmapImage(new Uri(@"F://Photos//Parthi//IMG_20141128_172826244.jpg"));                         
}

如果“STR”和“URI”没有必要由全班同学需要你可以直接将其添加到您的对象。 或者,如果你真的需要存储并重复使用您的数据,真正有规模庞大的金额你可以将其存储在物理文件上的临时文件,以防止内存泄露; 而不是将其存储到内存,你可以将其存储在物理存储。

希望能帮助到你



Answer 4:

Unload方法调用GetBitmap ,但GetBitmap每次都返回一个新的对象,所以据我所知,你从来没有真正要处理的img.Source正确



文章来源: Memory Leak in C# WPF