C#WPF中的内存泄漏 [英] Memory Leak in C# WPF

查看:182
本文介绍了C#WPF中的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在处置所有使用过的对象之后,我需要减少c#WPF中的内存泄漏.但是,使用以下代码片段无法完全减少内存消耗.

I need to reduce the memory leak in c# WPF after disposing all the used objects. But I couldn't reduce the memory consumption completely by using the following code snippet.

这是我的代码:

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;
}

运行示例后,在任务管理器中检查它时,产生了以下内存消耗读数,

After Running the sample, While checking it in Task manager, the following memory consumption reading has produced,

在点击加载"按钮之前:10.0 MB

Before "Load" Button is clicked : 10.0 MB

点击加载"按钮后:47.8 MB

After "Load" Button is clicked : 47.8 MB

点击卸载"按钮后:26.0 MB

After "Unload" Button is clicked : 26.0 MB

卸载后,我需要将内存减少到10.0 MB.因此,请对此提供帮助.

After Unloading, I need to reduce the memory closely to 10.0 MB. So please help me regarding this.

预先感谢.

推荐答案

首先,不要使用任务管理器来查看您的内存使用情况,因为它仅显示Windows进程分配的内存.有很多更好的工具,甚至Windows附带的性能监视器也可以让您更好地了解应用程序的性能以及任何内存泄漏.您可以通过运行perfmon.exe来启动它.

First of all, do not use Task Manager to view your memory usage, because it only shows the memory that the windows process allocates. There are plenty of much better tools out there and even the Performance Monitor, which comes on Windows, will give you a better idea of your application performance and any memory leaks. You may start it by running perfmon.exe.

在此示例应用程序中,直到堆达到大约85MB时,GC才会对集合进行攻击.而我为什么要呢?如果我决定再次使用相同的对象,那么它的内存并不多,并且可以很好地用作缓存解决方案.

In this sample application, GC does not become aggressive with collections until heap reaches approximately 85MB. And why would I want it to? It's not a lot of memory and it works very well as a caching solution, if I decide to use the same objects again.

因此,我建议您看一下该工具.它提供了一个很好的概览,它是免费的.

So, I suggest taking a look at that tool. It gives a nice overview of what's going on and it's free.

第二个,仅仅是因为您调用了.Dispose()来释放这些资源,并不意味着立即释放了内存.您基本上是在使它有资格进行垃圾收集,并且当GC到达时,它将进行处理.

Second of all, just because you called a .Dispose() to release those resources, does not mean that memory is released right away. You're basically making it eligible for the garbage collection and when GC gets to it, it'll take care of it.

WPF应用程序的默认垃圾收集行为是并发(< 4.0)/背景(4.0 =<)Workstation GC.它运行在一个特殊的线程上,大多数时候会尝试同时运行到应用程序的其余部分(我大部分时间都在说,因为有时它会非常短暂地挂起其他线程,以便完成清理工作. ).它不会等到内存用尽后才开始运行,但是同时,它只有在不严重影响性能的情况下才进行收集-一种平衡的权衡.

The default garbage collection behavior for a WPF application is Concurrent(<4.0)/Background(4.0=<) Workstation GC. It runs on a special thread and most of the time tries to run concurrently to the rest of the application (I say most of the time, because once in a while it'll extremely briefly suspend other threads, so that it may complete its cleanup). It doesn't wait until you're out of memory, but at the same time, it does collection only when it doesn't affect the performance greatly -- sort of a balanced trade-off.

要考虑的另一个因素是,您有一个0.643 MB jpeg文件,一旦计入BitmapImage,它就会更多……好​​吧,85,000 bytes以上的任何东西都被认为是一个大对象,因此,它被放置到第2代中,其中包含大对象堆.第2代垃圾回收非常昂贵,并且很少执行.但是,如果您正在运行.NET 4.5.1,但不确定是否运行,则可以强制进行压缩:

Another factor to consider is that you have a 0.643 MB jpeg file and once you count in BitmapImage, it's a bit more... well, anything above 85,000 bytes is considered to be a large object and thus, it is placed into generation 2, which contains the large object heap. Generation 2 garbage collection is expensive and is done infrequently. However, if you're running .NET 4.5.1, and I'm not sure if you are, you may force a compaction:

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

.Dipose()一样,这不会立即发生,因为这是一个昂贵的过程,并且比第一代小于一毫秒的扫描花费的时间更长.老实说,您可能甚至不会从中受益,因为我怀疑使用该应用程序,您在LOH中的碎片化程度很高.我刚刚提到了它,以便您在需要时知道该选项.

As with .Dipose(), this is not going happen right away, as it's an expensive process and it'll take a little longer than the generation 1 less-than-a-millisecond sweep. And honestly, you probably wouldn't even benefit from it, since I doubt that you would have a high fragmentation in the LOH with that application. I just mentioned it so that you're aware of that option if you ever need it.

那么,为什么我要向您简要介绍一下WPF应用程序(以及与此相关的大多数.NET应用程序)的默认GC行为?好了,了解GC的行为并确认其存在很重要.与C ++应用程序不同,在C ++应用程序中您被授予了对内存分配的大量控制权和自由度,.NET应用程序利用了GC.折衷方案是在由GC释放内存时将其释放.从您的角度来看,甚至有时它会过早地释放它,这时您可以通过调用GC.KeepAlive(..)显式地使对象保持活动状态.许多嵌入式系统没有使用GC,如果您想对内存进行非常精确的控制,建议您也不要使用.

So, why am I giving you a brief lesson on the default GC behavior of a WPF application (and most of .NET applications for that matter)? Well, it's important to understand the behavior of GC and acknowledge its existence. Unlike a C++ application, where you're granted a lot of control and freedom over your memory allocation, a .NET application utilizes a GC. The trade-off is that the memory is freed when it's freed by the GC. There may even be times when it frees it prematurely, from your point of view, and that's when you would explicitly keep an object alive by calling GC.KeepAlive(..). A lot of embedded systems do not make use of a GC and if you want very precise control over your memory, I suggest that you do not either.

如果您想了解.NET应用程序中内存的处理方式,强烈建议您对垃圾收集器的内部工作方法有所了解.我已经告诉您的是默认行为的简短快照,还有很多其他内容.有几种模式可以提供不同的行为.

If you want to be aware of how memory is being handled in a .NET application, I strongly recommend educating yourself on the inner workings of the garbage collector. What I've told you about is an incredibly brief snapshot of the default behavior and there is a lot more to it. There are a few modes, which provide different behaviors.

这篇关于C#WPF中的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆