我在多次使用 MemoryStream 时遇到问题。
Example:
For Each XImage As XImage In pdfDocument.Pages(pageCount).Resources.Images
Dim imageStream As New MemoryStream()
XImage.Save(imageStream, System.Drawing.Imaging.ImageFormat.Jpeg)
' some further processing
imageStream.Close()
imageStream.Dispose()
Next
这段代码循环浏览 PDF 文件页面上的图像。该文件最多可能有 cca 500 页,假设每页有 5 个图像。它会导致数千次迭代。问题是 MemoryStream 未释放,导致内存不足异常。 XImage 通常约为 250 kB。
我在这里使用 Aspose.PDF 库来处理 PDF(XImage 是该库中的一个类),但这并不重要。我尝试制作一个简单的示例,其中我只是创建一个新的 MemoryStream 并向其中保存一个虚拟位图。它会导致同样的问题。
我还尝试使用 FileStream 而不是 MemoryStream,但其行为相同。
任何帮助表示赞赏。
Thanks
Jiri
流中的内存被释放。我答应你。确实如此。
没有被释放的是地址空间在您的应用程序中以前被该内存占用。您的计算机有足够的内存可用,但您的特定应用程序崩溃了,因为它无法在地址表中找到可以分配更多内存的位置。
达到限制的原因是 MemoryStream 在增长时会回收其缓冲区。它内部使用 byte[] 来保存其数据,并且默认情况下将数组初始化为一定的大小。当您写入流时,如果超出数组的大小,流将使用加倍算法来分配新数组。然后信息从旧数组复制到新数组。此后,旧数组可以并且将会被收集,但它不会被压缩(认为:碎片整理)。结果是程序的虚拟地址表中出现了漏洞,这些漏洞对于 MemoryStream 缓冲区而言不再足够大。一个 MemoryStream 可能使用多个数组,从而导致多个内存漏洞,其总地址空间可能比源数据大得多。
AFAIK,目前无法强制垃圾收集器压缩内存地址空间。因此,解决方案是分配一个可以处理最大图像的大块,然后一遍又一遍地重复使用同一块,这样您就不会得到无法到达的内存地址。
对于此代码,这意味着在循环外部创建 MemoryStream,并将整数传递给构造函数,以便将其初始化为合理的字节数。您会发现这也给您带来了很好的性能提升,因为您的应用程序突然不再花时间频繁地将数据从一个字节数组复制到另一个字节数组,这意味着即使您可以压缩地址表,这也是更好的选择:
Using imageStream As New MemoryStream(307200) 'start at 300K... gives you some breathing room for larger images
For Each XImage As XImage In pdfDocument.Pages(pageCount).Resources.Images
'reset the stream, but keep using the same memory
imageStream.Seek(0, SeekOrigin.Begin)
imageStream.SetLength(0)
XImage.Save(imageStream, System.Drawing.Imaging.ImageFormat.Jpeg)
' some further processing
Next
End Using
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)