1

我正在使用在代码项目中找到的 DLL 在 VB.NET 中处理 PDF:

http://www.codeproject.com/Articles/37458/PDF-Viewer-Control-Without-Acrobat-Reader-Installe

我的应用程序允许您在网格中选择多个文件并打印它们。这些文件存储在受密码保护的 zip 文件中,因此我要做的第一步是将每个选定的文件提取到我传递给新 PDF 包装器对象的内存流中。每个对象都被添加到队列中。然后,将队列中的每个对象逐页打印为 system.drawing.image。整个事情在后台工作人员上运行。

现在,将 PDF 提取到队列中几乎不会占用任何内存。但是在 PrintPage 事件处理程序中,当我提取图像并将它们发送到打印机时,一定有问题。我的内存使用量激增。当然,每个图像都很大,因为它以 300 dpi 渲染,但是每个页面使用的内存没有返回给操作系统,也没有被垃圾收集。

最后,如果我选择了足够多的文件,我的内存就会用完。为什么?

4

1 回答 1

1

好的,所以我终于想通了。

首先,就图像而言,CLR 显然不知道为 a 分配了多少内存,Drawing.Image所以当你处理它时,你必须告诉它:

'It's 4 bytes per pixel with RGBA
'Use Drawing.Image.PixelFormat to get
'the number of bytes if you don't know
Dim countBytes as long = 4 * img.Width * img.Height

'Let the CLR know of the memory we want to free
if countBytes > 0 then GC.AddMemoryPressure(countBytes)

'Get rid of the image
img.Dispose()
img = Nothing

'Free up the unused memory
GC.Collect()

'Tell the CLR we took care of it
GC.RemoveMemoryPressure(countBytes)

现在,CodeProject 示例中的 PDF 库要困难得多。

首先,确保在包含包装器的表单的事件中或在包含它的类的方法中调用对象Dispose上的方法。PDFWrapperFormClosedFinalize

但是,PDFWrapper实际上似乎缓存了您从中检索到的图像。因此,当您翻阅 PDF 时,内存使用量会增加,直到整个 PDF 的图像都被缓存。如果您使用这些图像以 300DPI 打印 PDF,这是一个更大的问题(在使用 1.5GB 内存的情况下,我在 60 多页 PDF 的末尾出现内存不足错误)。

据我所知,这个对象没有“清除缓存”方法。但是我用来让它工作的技巧是在我得到我需要的图像后以 1DPI 抓取图像,然后像上面那样执行垃圾收集。这间接释放了缓存的内存。但是,像以前一样,我们必须告诉 CLR 我们使用了多少字节。和上面的计算是一样的。

但是还有一个问题。PDFWrapper看起来,该对象实际上是在另一个线程上抓取图像。因此,通过在我们请求 300DPI 图像后请求另一个 1DPI 图像,它会感到困惑,并在应该给我们 300DPI 图像打印时随机吐出 1DPI 图像。因此,解决此问题的方法:

Dim img As System.Drawing.Image
img = AFPDFLibUtil.GetImageFromPDF(pdfWrapper, currentPage, DPI)

'Wait for PDFWrapper to finish rendering
Dim sw As New Stopwatch()
sw.Start()
While _pdfWrapper.IsBusy
    If sw.ElapsedMilliseconds < TimeoutMS Then
        System.Threading.Thread.Sleep(10)
    Else
        Throw New Exception("This page took too long to render.")
    End If
End While
sw.Stop()
sw.Reset()

你去吧。也许这就是为什么在 CodeProject 示例中,他使用不同的 DLL 进行打印。但是,该PDFWrapper对象支持从 a 读取IO.MemoryStream,我认为该项目中的任何其他包含都不支持。

祝所有阅读本文的人编码愉快!

于 2012-06-19T20:36:00.993 回答