2014-12-03 60 views
1

我需要在處理所有使用的對象後減少c#WPF中的內存泄漏。但是我不能完全通過使用下面的代碼片段來減少內存消耗。在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; 
} 

運行示例,而在任務管理器檢查它,下面的內存消耗閱讀已經產生,

之前「Load」按鈕點擊後:10.0 MB

後 「Load」 按鈕被點擊:47.8 MB

後 「卸載」 按鈕被點擊:26.0 MB

卸載後,我需要將內存緊密地減少到10.0 MB。所以請幫助我解決這個問題。

在此先感謝。

+0

在'Unload'函數末尾調用'GC.Collect()' – dotctor 2014-12-03 06:12:01

+0

'Bitmap'繼承自'Image',它實現了'IDisposable' ...爲什麼不只是利用它並使用'using'呢?順便說一句,爲什麼你有這樣嚴格的要求,你不能讓WPF和.NET爲你處理內存?我可能是錯的,但是我覺得如果你想要這樣的微觀管理水平,C或C++可能是更好的選擇。 – 2014-12-03 06:23:06

+1

你在閱讀什麼記憶指標? – leppie 2014-12-03 07:25:18

回答

2

使用.net平臺無法控制內存,就好象它在c/C++中工作 垃圾回收器操作非常複雜的策略,並且事實上,您將內存降至26但10是正常的。.net保留了一個空間來爲更快的數據充電,並保證主存儲器中的空閒空間,而不需要連續的操作系統。

我注意到的是完全正常的。 這在過去我個人的課程

查看此過程中受到微軟的MVP了一個問題: http://msdn.microsoft.com/en-us/library/ee787088%28v=vs.110%29.aspx

這:Best Practice for Forcing Garbage Collection in C#

0

嘗試管理你的變量的使用。你可以做這樣的事情:

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

如果「海峽」和「URI」沒有必要由全班同學需要你可以直接將其添加到您的對象。或者,如果您真的需要存儲它並重新使用真正具有大量數據量的數據,則可以將其存儲在臨時文件上的物理文件中以防止內存泄漏;而不是將其存儲到內存中,您可以將其存儲在物理存儲上。

希望它有助於

+1

這將分配相等數量的內存。只要你實例化一個對象,它就會分配內存。無論是否內聯都沒關係。該變量的範圍是該方法。因此,只有在方法結束後,纔會釋放內存(並且當對象是一個可丟棄對象時調用該對象時)。 – woutervs 2014-12-12 08:44:04

0

Unload方法調用GetBitmap,但GetBitmap每次都返回一個新的對象,所以據我所知,你從來沒有真正要處理的img.Source正確

2

第一總之,不要使用任務管理器來查看您的內存使用情況,因爲它只顯示Windows進程分配的內存。這裏有很多更好的工具,甚至Windows上的性能監視器也能讓你更好地瞭解你的應用程序性能和任何內存泄漏。您可以通過運行perfmon.exe來啓動它。

在本示例應用程序中,GC不會對集合產生積極影響,直到堆達到大約85MB。我爲什麼要這樣做?如果我決定再次使用相同的對象,它並不是很多內存,並且它可以很好地用作緩存解決方案。

enter image description here

所以,我建議考慮看看該工具。它給出了一個很好的概述,它是免費的。

其次,僅僅因爲您調用.Dispose()來釋放這些資源,並不意味着內存會立即釋放。你基本上可以使它符合垃圾收集的條件,當GC達到它時,它會處理它。

WPF應用程序的默認垃圾回收行爲是Concurrent(< 4.0)/ Background(4.0 = <)Workstation GC。它運行在一個特殊的線程上,大部分時間都試圖同時運行到應用程序的其他部分(我說大部分時間,因爲偶爾會暫時掛起其他線程,以便它可以完成清理)。它不會一直等到內存不足,但同時它只在不會對性能產生重大影響時才進行收集 - 這種平衡的平衡。

另一個需要考慮的因素是,你有一個0.643 MB JPEG文件,一旦你在BitmapImage算,它是多一點......嗯,什麼事上面85,000 bytes被認爲是一個大的對象,因此,它被置入代2,其中包含大對象堆。第2代垃圾收集非常昂貴並且很少進行。但是,如果你正在運行的.NET 4.5.1,我不知道,如果你是,你可能會迫使壓實:

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

.Dipose(),這是不會馬上發生,因爲它是一個昂貴的過程,它會比第一代少於一毫秒的掃描花費更長的時間。說實話,你可能甚至不會從中受益,因爲我懷疑你在LOH中會有很高的碎片。我剛纔提到過,所以如果你需要的話,你會意識到這個選擇。

那麼,我爲什麼要給你一個關於WPF應用程序(以及大多數.NET應用程序)的默認GC行爲的簡短課程?那麼瞭解GC的行爲並確認它的存在就很重要。與C++應用程序不同的是,.NET應用程序使用GC,而您在內存分配方面獲得了很多控制和自由。權衡是當GC釋放內存時釋放內存。從你的角度來看,甚至有時候它會過早地將它釋放出來,那就是通過調用GC.KeepAlive(..)來明確保留一個對象。許多嵌入式系統不使用GC,如果你想精確控制你的內存,我建議你不要。

如果您想了解.NET應用程序中內存的處理方式,我強烈建議您自己介紹一下垃圾回收器的內部工作原理。我告訴你的是默認行爲的一個非常簡短的快照,還有更多。有幾種模式可以提供不同的行爲。