.net MemoryStream使用导致内存不足异常

.net MemoryStream使用导致内存不足异常,.net,vb.net,memorystream,.net,Vb.net,Memorystream,我在多次使用MemoryStream时遇到问题 例如: 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 ima

我在多次使用MemoryStream时遇到问题

例如:

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文件页面上的图像。该文件可能有多达500页,假设每页有5幅图像。它会导致数千次迭代。问题是MemoryStream没有被释放,这会导致内存不足异常。XImage通常有250 kB左右

我在这里使用Aspose.PDF库来处理PDF(XImage是这个库中的一个类),但这并不重要。我试着做一个简单的例子,创建一个新的MemoryStream并保存一个虚拟位图。这导致了同样的问题

我还尝试使用FileStream而不是MemoryStream,但其行为相同

谢谢你的帮助

谢谢


Jiri

从流中释放内存。我向你保证。真的,是的

没有释放的是应用程序中以前由该内存占用的地址空间。您的计算机有很多可用的ram,但是您的特定应用程序崩溃了,因为它无法在地址表中找到一个位置来分配更多的内存

达到该限制的原因是MemoryStream在其增长时会回收其缓冲区。它在内部使用字节[]保存数据,默认情况下,数组初始化为特定大小。在写入流时,如果超过数组的大小,则流将使用加倍算法来分配新数组。然后将信息从旧阵列复制到新阵列。在此之后,旧阵列可以也将被收集,但不会被压缩(想想:碎片整理)。结果是程序虚拟地址表中的漏洞不再足以容纳MemoryStream缓冲区。一个MemoryStream可能会使用多个数组,从而导致多个内存孔,其总地址空间可能比源数据大得多

好吧,现在没有办法强制垃圾收集器压缩内存地址空间。因此,解决方案是分配一个可以处理最大映像的大块,然后反复使用同一块,这样就不会得到无法访问的内存地址

对于这段代码,这意味着在循环外部创建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

谢谢乔尔的精彩解释,我很感激。我尝试了建议的方法,但问题仍然存在,即使我将MemoryStream初始化为不同的字节数。谢谢你的帮助。你知道这些图片的大小吗?也有可能pdfDocument在创建你的XImage资源对象时也在做同样的事情,在这种情况下,你需要重新考虑整个事情,因为当前的方法是注定要失败的。啊:刚刚看到它们是250K。另外,我们在“进一步处理”部分遗漏了很多可能会占用地址空间的内容。谢谢,我认为PDF文档是无辜的。我用纯System.Drawing.Bitmap复制了它,该位图填充了一个虚拟图像并保存到MemoryStream中。还跳过了隔离问题的所有进一步处理。无论如何,谢谢。如果你根本不创建内存流,也不保存图像,看看会发生什么,这会很有趣。是否
文档
类正在缓存图像,以便下次不必重建它们?