在我们的应用程序中,我们正在使用 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/