2013-08-26 7 views
0

Я уверен, что решение этого просто, но я остаюсь царапать голову, поэтому, возможно, кто-то может пролить свет здесь.Утечка памяти при обновлении фона холста WPF

Что я делаю, когда запускается моя программа Загружает входной файл в приватную переменную (_bmpSource) и отображает ее на холсте, создавая ImageBrush и устанавливая фон холста. Нажатием кнопки я изменяю изображение, поворачивая его, а затем отображаю его, снова устанавливая свойство фона холста. Похоже, что я неправильно управляю памятью, потому что операция поворота/отображения работает правильно для нескольких итераций, но в конечном итоге будет бояться жаловаться на недостаточную память.

ПРИМЕЧАНИЕ: Изображение, которое я использую, составляет 5000x5000 пикселей.

Я пробовал все: от перерыва ссылок на вызов коллекции мусора, но кажется, что холст все еще держится за эти данные.

Вот пример кода, с которым я могу воспроизвести проблему.

Частные объявления переменных:

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 
+0

Вы можете избавиться от TranslateTransform, потому что вы говорите, что RotateTransform поворачивается по центру изображения. – Nick

+0

Я верю, что если бы я центрировал изображение на холсте, тогда вы были бы правы. Он не показывает это в этом примере кода, но я фактически выравниваю вверху слева, и в этом случае необходим перевод. – user2719109

ответ

0

GC как-то не хватило времени на выпуск памяти. Добавьте этот код в конце вашего метода или в каждом цикле.

System.GC.Collect() 
System.GC.WaitForPendingFinalizers() 
Смежные вопросы