c# - 从 PackagePart 流读取不释放内存

标签 c# memory stream package xps

在我们的应用程序中,我们正在使用 System.IO.Packaging.Package 类读取 XPS 文件。当我们从 PackagePart 的流中读取时,我们可以从任务管理器中看到应用程序的内存消耗增加了。但是,当读取完成后,内存消耗不会回落到从流读取之前的状态。

为了说明问题,我编写了一个简单的代码示例,您可以在独立的 wpf 应用程序中使用它。

 public partial class Window1 : Window
 {
        public Window1()
        {
            InitializeComponent();

            _package = Package.Open(@"c:\test\1000pages.xps", FileMode.Open, FileAccess.ReadWrite, FileShare.None);

        }

        private void ReadPackage()
        {
            foreach (PackagePart part in _package.GetParts())
            {
                using (Stream partStream = part.GetStream())
                {
                    byte[] arr = new byte[partStream.Length];
                    partStream.Read(arr, 0, (int)partStream.Length);
                    partStream.Close();
                }
            }
        }

        Package _package;
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ReadPackage();      
        }
 }

ReadPackage() 方法会将所有 PackagePart 对象的流内容读取到本地数组中。在示例中,我使用了一个 1000 页的 XPS 文档作为包源,以便轻松查看应用程序的内存消耗变化。在我的机器上,独立应用程序的内存消耗从 18MB 开始,然后在调用该方法后上升到 100MB。再次调用该方法会再次增加内存消耗,但会回落到 100MB。但是,它不会再回落到 18MB。

有人在使用 PackagePart 时遇到过这种情况吗?还是我用错了?我认为 PackagePart 的内部实现正在缓存读取的数据。

谢谢!

最佳答案

您没有指定如何测量应用程序的“内存消耗”,但也许您正在使用任务管理器?为了更好地了解正在发生的事情,我建议您检查应用程序的一些性能计数器。 .NET 堆和一般进程内存性能计数器均可用。

如果你真的想了解你的应用程序如何使用内存的细节,你可以使用 Microsoft CLR profiler .

您看到的可能是 .NET 堆扩展以容纳非常大的文件的结果。大对象放在大对象堆 (LOH) 上,即使 .NET 内存被垃圾收集,空闲内存也永远不会返回给操作系统。此外,在垃圾收集期间,LOH 上的对象永远不会四处移动,这可能会使 LOH 碎片化,耗尽可用地址空间,即使有足够的空闲内存也是如此。

Has anyone experienced this while using PackagePart? Or am I using it wrong?

如果你想控制包使用的资源,你就没有以最好的方式使用它。包是一次性的,通常你应该这样使用它:

using (var package = Package.Open(@"c:\test\1000pages.xps", FileMode.Open, FileAccess.ReadWrite, FileShare.None)) {
  // ... process the package
}

using 语句结束时,包消耗的资源要么已经被释放,要么可以被垃圾回收。

如果您真的想保留表单的 _package 成员,您应该在某个时候调用 Close()(或 IDisposable.Dispose()) 释放资源。不推荐调用 GC.Collect() 并且不一定能够回收包使用的资源。任何可从 _package 访问的托管内存(例如包缓冲区)都不会被垃圾回收,无论您尝试强制垃圾回收的频率如何。

关于c# - 从 PackagePart 流读取不释放内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3819564/

相关文章:

c++ - 如何制作在每次输出操作后插入新行的流?

Python:tarfile 流

Common Lisp 中用于数据压缩的流接口(interface)

c# - 如何计算目录中文件的匹配数

c - 为什么这些调用具有相同的内存地址?

python - 在 Virtualenv 中测试 python 框架的内存使用情况

.net - 生成报告时诊断 .NET OutOfMemoryException

c# - 在 C# 应用程序 + ip :port proxy 中使用 fiddler

c# - 我可以使用 Node.js 调用 C# 方法吗?

c# - 更改 Kendo UI 上传小部件的文本