更新WPF画布背景时内存泄漏

时间:2013-08-26 21:39:03

标签: .net wpf imaging

我确信解决这个问题的方法很简单,但我只是在摸不着头脑,所以也许有人可以在这里说清楚。

我正在做的是当我的程序启动时,我将输入文件加载到私有变量(_bmpSource)中,并通过创建ImageBrush并设置画布的背景在Canvas中显示它。在按钮上单击我通过旋转它来修改图像,然后再次通过设置画布的背景属性来显示它。似乎我对内存管理不善,因为旋转/显示操作在几次迭代中正常工作,但最终会炸弹抱怨内存不足。

注意:我正在使用的图像为5000x5000像素bmp。

我已经尝试了从破坏引用到调用垃圾收集的所有内容,但看起来画布仍以某种方式保留此数据。

以下是一些我可以重现问题的示例代码。

私有变量声明:

Private _SourceFileName As String = "C:\Users\sean\Desktop\Input.bmp"
Private _bmpSource As BitmapSource

在我的构造函数中调用它来初始加载/显示图像:

Me._bmpSource = Me.LoadImage()
Me._Canvas.Background = New System.Windows.Media.ImageBrush(Me._bmpSource)

LoadImage()实现:

Private Function LoadImage() As BitmapImage

    Dim bmpImage As New BitmapImage
    Dim imageSourceStream As New FileStream(Me._SourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read)
    Dim decoder As New BmpBitmapDecoder(imageSourceStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
    Dim encoder As New JpegBitmapEncoder

    encoder.Frames.Add(BitmapFrame.Create(decoder.Frames(0)))

    Dim streamSourcePath As String = My.Computer.FileSystem.GetTempFileName
    Dim Stream As New System.IO.FileStream(streamSourcePath, FileMode.OpenOrCreate, FileAccess.Write)

    encoder.Save(Stream)
    Stream.Close()
    Stream = Nothing

    bmpImage.BeginInit()
    bmpImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache
    bmpImage.CacheOption = BitmapCacheOption.OnLoad
    bmpImage.UriSource = New Uri(streamSourcePath)
    bmpImage.EndInit()

    Return bmpImage
End Function

这是RotateImage()实现,它在按钮点击事件后面运行:

Public Sub RotateImage()

    ' Store our source rect for use in applied transforms
    Dim ImageRect As New System.Drawing.RectangleF(System.Drawing.PointF.Empty, New System.Drawing.SizeF(Me._bmpSource.Width, Me._bmpSource.Height))

    ' Store our target rect for use in applied transforms
    ' NOTE: For this demo we're always rotating 90 degrees so just flip height/width
    Dim CanvasRect As System.Drawing.RectangleF = New System.Drawing.RectangleF(System.Drawing.Point.Empty, New System.Drawing.SizeF(Me._bmpSource.Height, Me._bmpSource.Width))

    ' Figure out the point in which we will need to draw the image
    ' to fit it within the bounds of our canvas rectangle
    Dim WidthOffset As Decimal = (CanvasRect.Width - ImageRect.Width) / 2
    Dim HeightOffset As Decimal = (CanvasRect.Height - ImageRect.Height) / 2

    ' Build transform needed for rotate
    Dim transformActions As New System.Windows.Media.TransformGroup
    transformActions.Children.Add(New System.Windows.Media.RotateTransform(90, Me._bmpSource.Width / 2, Me._bmpSource.Height / 2))
    transformActions.Children.Add(New System.Windows.Media.TranslateTransform(WidthOffset, HeightOffset))

    ' Apply the transformation to the image
    Dim transformedBitmap As New System.Windows.Media.Imaging.TransformedBitmap(Me._bmpSource, transformActions)

    ' Trying to break references here so things will get disposed but it isn't working
    If TypeOf Me._bmpSource Is BitmapImage Then
        CType(Me._bmpSource, BitmapImage).StreamSource = Nothing
    ElseIf TypeOf Me._bmpSource Is TransformedBitmap Then
        CType(Me._bmpSource, TransformedBitmap).Source = Nothing
    End If

    ' Breaking main ref also doesn't help
    Me._bmpSource = Nothing

    ' Garbage collection does nother either
    GC.WaitForPendingFinalizers()
    GC.Collect()

    Me._bmpSource = transformedBitmap
    Me._Canvas.Background = New System.Windows.Media.ImageBrush(Me._bmpSource)
    Me._Canvas.UpdateLayout()
End Sub

1 个答案:

答案 0 :(得分:0)

GC不知何时没有足够的时间释放内存。 在方法结束时或每个循环中添加此代码。

System.GC.Collect()
System.GC.WaitForPendingFinalizers()