5

在我们的应用程序中,我们正在使用 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 的内部实现是缓存读取的数据。

谢谢!

4

1 回答 1

0

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

如果您真的想了解应用程序如何使用内存的详细信息,可以使用Microsoft CLR 分析器

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

有人在使用 PackagePart 时遇到过这种情况吗?还是我用错了?

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

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不会被垃圾收集。

于 2010-09-29T07:53:34.607 回答