好的,所以我终于想通了。
首先,就图像而言,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
上的方法。PDFWrapper
FormClosed
Finalize
但是,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
,我认为该项目中的任何其他包含都不支持。
祝所有阅读本文的人编码愉快!