WPF图像处理 - 永不释放内存

时间:2010-11-05 16:35:13

标签: wpf image-processing

我正在编写一个应用程序来读取一个非常大的tif文件(15000x10000),然后将其切割成256x256磁贴,并将其保存为jpeg。我正在尝试使用WPF windows.media.imaging对象来进行切割。下面的例子运行正常并将为我提取一些图块(它只是为此示例获取相同图块的多个副本)但应用程序耗尽内存并且该内存永远不会被释放。即使强制CG.Collect测试它仍然不会释放内存。

 Dim croppedImage As CroppedBitmap

 Dim strImagePath As String = "C:\Huge.tif"

  Dim imageSource As BitmapSource = TiffBitmapDecoder.Create(New Uri(strImagePath), BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.None).Frames(0) 'CreateImage(imageBytes, 0, 0)
  Dim enc As JpegBitmapEncoder
  Dim stream As FileStream

  For i As Integer = 0 To 5000
      croppedImage = New CroppedBitmap()

      croppedImage.BeginInit()
      croppedImage.Source = imageSource
      croppedImage.SourceRect = New Int32Rect(0, 0, 256, 256)
      croppedImage.EndInit()

      enc = New JpegBitmapEncoder()
      enc.QualityLevel = 70
      enc.Frames.Add(BitmapFrame.Create(croppedImage))
      stream = New FileStream("C:\output\" & i & ".jpg", FileMode.Create, FileAccess.Write)
      enc.Save(stream)
      stream.Close()

      enc = Nothing
      stream = Nothing
      croppedImage.Source = Nothing
      croppedImage = Nothing

  Next

  imageSource = Nothing

我错过了一些基本的东西吗?如何确保正确发布这些资源?

由于

更多信息:

下面提供的答案肯定有帮助。感谢那。我现在还有另一个问题要添加到此。我想通过添加以下代码来保存每个磁贴之前的水印:

Dim targetVisual = New DrawingVisual()
Dim targetContext = targetVisual.RenderOpen()

targetContext.DrawImage(croppedImage, New Rect(0, 0, tileWidth, tileHeight))
targetContext.DrawImage(watermarkSource, New Rect(0, 0, 256, 256))

Dim target = New RenderTargetBitmap(tileWidth, tileHeight, 96, 96, PixelFormats.[Default])

targetContext.Close()
target.Render(targetVisual)
Dim targetFrame = BitmapFrame.Create(target)

这开始使用一些严肃的记忆。根据任务管理器的报告,运行大型tif使用超过1200MB的内存。看起来这个内存最终会被释放,但是我有点担心代码中的某些东西是不对的,并且无论如何都要阻止它首先占用所有这些内存。也许这仅仅是弗朗西讨论过的问题?

安德鲁

3 个答案:

答案 0 :(得分:0)

在循环中~25000对象分配之后,你的大对象肯定会升级到第2代。 Gen 2对象仅在完整集合上收集,这些对象很少完成,因此您的对象可能会在内存中停留一段时间。

您可以尝试使用GC.Collect()强制完整收藏。在强制完全分配之前,您还可以使用其他GC方法检查分配的内存,然后等待它完成,然后再次检查分配的内存以确定是否确实收集了大对象。

请注意,即使可能发生完整集合,内存也已包含在进程工作集中,操作系统可能需要做一些反应才能释放该内存并将其从工作集中删除。如果您试图通过查看任务管理器中的进程工作集来判断内存是否正确收集,请务必记住这一点。

答案 1 :(得分:0)

我在本地重新创建了您的代码并进行了一些小型实验,因此我发现如果您将stream置于for循环中并使用enc.SaveUsing stream As New FileStream(System.IO.Path.Combine(outputDir, i.ToString() & ".jpg"), FileMode.Create, FileAccess.Write)总数私有字节大约保持在60 MB(在using内未使用时为80+ MB)。

我的完整代码供您参考:

Dim fileName As String = System.IO.Path.Combine(Environment.CurrentDirectory, "Image1.tif")
Dim outputDir As String = System.IO.Path.Combine(Environment.CurrentDirectory, "Out")

Dim imageSource As BitmapSource = TiffBitmapDecoder.Create(New Uri(fileName), BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.None).Frames(0)

Dim enc As JpegBitmapEncoder
Dim croppedImage As CroppedBitmap

For i As Integer = 0 To 4999
    croppedImage = New CroppedBitmap()

    croppedImage.BeginInit()
    croppedImage.Source = imageSource
    croppedImage.SourceRect = New Int32Rect(0, 0, 256, 256)
    croppedImage.EndInit()

    enc = New JpegBitmapEncoder()
    enc.QualityLevel = 70
    enc.Frames.Add(BitmapFrame.Create(croppedImage))
    Using stream As New FileStream(System.IO.Path.Combine(outputDir, i.ToString() & ".jpg"), FileMode.Create, FileAccess.Write)
        enc.Save(stream)
    End Using

    enc = Nothing
    croppedImage.Source = Nothing

    croppedImage = Nothing
Next

imageSource = Nothing

答案 2 :(得分:0)

尝试创建你的TiffBitmaDecoder:

Dim imageSource As BitmapSource = TiffBitmapDecoder.Create(New Uri(fileName), BitmapCreateOptions.IgnoreImageCache, BitmapCacheOption.OnLoad).Frames(0)