2017-05-16 36 views
0

我正在使用RenderTargetBitmap來渲染一組控件以生成PDF。下面的代碼段的相關部分:RenderTargetBitmap中的內存泄漏

public Drawing.Image RenderPageBitmap() 
{ 
    RenderTargetBitmap bit = null; 
    Drawing.Bitmap bmp = null; 
    try 
    { 
     bit = new RenderTargetBitmap(ImageSource.PixelWidth, ImageSource.PixelHeight, 96, 96, PixelFormats.Pbgra32); 

     var viewBox = GetPageXaml(); //This method loads some prebuilt XAML from an embedded resource, setting the DataContext as needed. 
     var siz = new Size(bit.PixelWidth, bit.PixelHeight); 
     viewBox.Measure(siz); 
     viewBox.Arrange(new Rect(siz)); 
     viewBox.UpdateLayout(); 

     var draw = new DrawingVisual(); 
     using (var graph = draw.RenderOpen()) 
      graph.DrawRectangle(new BitmapCacheBrush(viewBox), null, new Rect(siz)); 

     bit.Render(draw); 
     bit.Freeze(); 

     bmp = new Drawing.Bitmap(bit.PixelWidth, bit.PixelHeight, Imaging.PixelFormat.Format32bppPArgb); 

     var data = bmp.LockBits(new Drawing.Rectangle(Drawing.Point.Empty, bmp.Size), ImageLockMode.WriteOnly, Imaging.PixelFormat.Format32bppPArgb); 
     { 
      bit.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); 
     } 
     bmp.UnlockBits(data); 

     return bmp; 
    } 
    catch (Exception) 
    { 
     bmp?.Dispose(); 
     throw; 
    } 
    finally 
    { 
     bit?.Clear(); 

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

即使以下StackOverflow上其他的答案和其他論壇(如清除位圖,並進行垃圾收集)似乎並沒有解決問題。這段代碼的每個循環都會泄漏〜100MB的內存,這意味着我很快就會達到32位進程的〜2GB限制。

泄漏似乎只發生在RenderTargetBitmap.Render方法上,即使調用DrawingContext.DrawRectangle也不會明顯增加內存使用量。

我能做些什麼來解決這個問題嗎?

下面是通過JetBrains的dotMemory查看的內存使用情況的快照。顯然,.NET堆被正確清除,但非託管內存繼續增長。

Memory snapshot

+0

@Downvoter,小心解釋一下? –

+0

您是否假設存在內存泄漏或者您確實遇到了OutOfMemoryException?我已經更新了我的答案。順便說一句,我沒有投票。 – CharithJ

+0

你怎麼知道它是有內存泄漏的RenderTargetBitmap? viewBox元素如何?在問這個問題之前,你一定要使用內存分析器。 – Clemens

回答

-1

根據我的考察,draw分配DrawingVisual對象。

除非Render()釋放它,你應該明確地刪除DrawingVisual對象。

+2

'DrawingVisual'是一個WPF類,它沒有任何'Close','Dispose'或'Delete'方法。 –

0

您將Bitmap返回到某處。確保在完成之後配置位圖實例。當存在內存泄漏時,finally中正在執行的操作是無用的。如果有引用,GC不會收集它。

此代碼的每個循環都可能會泄漏〜100MB的內存,這意味着我的 快速達到了32位進程的〜2GB限制。

您是否假設存在內存泄漏?可能沒有內存泄漏。我會得到一個很好的內存分析工具並對其進行測試。

我已經使用ANTS Memory profiler,我覺得它很好(它有14天的試用期)。只需執行幾次邏輯並查看實例列表是否有任何增長。如果是這樣,看看保留圖,看看它保留了什麼。這將告訴你究竟發生了什麼。內存泄漏的根本原因有時很難被猜出,幸運的是有很好的工具。

+0

內存泄漏發生在非託管內存中。這種垃圾收集技術被推薦用於'RenderTargetBitmap's。 'Bitmap'被包含在調用者的using塊中。 –

+0

@PeterDuniho'System.Drawing.Bitmap'絕對實現'IDisposable':https://msdn.microsoft.com/en-us/library/8th8381z(v=vs.110).aspx –

+0

@la:我指的是'RenderTargetBitmap'。你沒有顯示方法聲明,所以我不清楚你所描述的代碼是處理不同的'Bitmap'類。 –

1

刪除bit.Freeze();。垃圾收集不收集凍結的對象。