12

在具有 16GB RAM 的 Windows Server 2008 x64 上运行 .NET 应用程序。该应用程序需要获取和分析非常大量的数据(大约 64GB),并且一次将其全部保存在内存中。

我期望看到的:进程大小从 16GB 扩展到 64GB。Windows 使用虚拟内存根据需要将额外数据分页到磁盘或从磁盘分页。这是经典的虚拟内存用例。

我实际看到的:进程大小仅限于物理内存量(16GB)。应用程序将 99.8% 的时间花在垃圾收集器上。

为什么我们的应用程序无法使用虚拟内存?这是 .NET 垃圾收集器的配置问题,还是 Windows x64 虚拟内存管理器本身的问题?我该怎么做才能让我们的应用程序使用虚拟内存而不是仅限于物理内存?

谢谢。

——布赖恩

更新:我编写了一个非常小的程序,它表现出相同的行为:

using System;

namespace GCTest
{
    class Program
    {
        static void Main()
        {
            byte[][] arrays = new byte[100000000][];
            for (int i = 0; i < arrays.Length; ++i)
            {
                arrays[i] = new byte[320];
                if (i % 100000 == 0)
                {
                    Console.WriteLine("{0} arrays allocated", i);
                    System.Threading.Thread.Sleep(100);
                }
            }
        }
    }
}

如果您想尝试它,请确保为 x64 构建。您可能需要稍微修改常量以对系统施加压力。我看到的行为是进程在接近 16GB 大小时陷入困境。没有错误消息或异常抛出。性能监视器报告 GC 中的 CPU 时间百分比接近 100%。

这不是不能接受吗?虚拟内存系统在哪里?

4

2 回答 2

10

您是否检查过以确保您的页面文件已配置为可以扩展至该大小?

更新

我一直在用你给出的例子来解决这个问题,这就是我所看到的。

系统:Windows 7 64bit,6GB 三通道 RAM,8 核。

  1. 您需要在您的操作系统的另一个主轴上添加一个额外的页面文件,否则这种调查将占用您的机器。如果一切都在为同一个页面文件而战,那会让事情变得更糟。

  2. 我看到大量数据在 GC 中代代相传,加上大量的 GC 扫描\收集,以及由于达到物理内存限制而导致的大量页面错误。我只能假设,当物理内存耗尽\非常高时,这会触发生成扫描和提升,从而导致大量已调出的内存被触动,这将导致死亡螺旋,因为触动的内存被调入和其他内存被迫退出。整个事情以湿透的烂摊子告终。当分配大量最终在小对象堆中的长寿命对象时,这似乎是不可避免的。

现在将此与分配对象的方式进行比较,将它们直接分配到大对象堆中(不会遇到相同的清除和提升问题):

private static void Main()
{
    const int MaxNodeCount = 100000000;
    const int LargeObjectSize = (85 * 1000);

    LinkedList<byte[]> list = new LinkedList<byte[]>();

    for (long i = 0; i < MaxNodeCount; ++i)
    {
        list.AddLast(new byte[LargeObjectSize]);

        if (i % 100000 == 0)
        {
            Console.WriteLine("{0:N0} 'approx' extra bytes allocated.",
               ((i + 1) * LargeObjectSize));
        }
    }
}

这按预期工作,即使用虚拟内存,然后最终耗尽 - 在我的环境\配置中为 54GB。

因此,分配大量长寿命的小对象似乎最终会导致 GC 中的恶性循环,因为当物理内存耗尽时会进行世代扫描和提升 - 这是一个页面文件死亡螺旋。

更新 2

在调查这个问题时,我使用了一些没有明显区别的选项\配置:

  • 强制服务器 GC 模式。
  • 配置低延迟 GC。
  • 强制GC尝试摊销GC的各种组合。
  • Min\Max 流程工作集。
于 2010-06-22T14:57:48.813 回答
2

听起来您没有保留对大数据的引用。垃圾收集器不会收集引用的对象。

于 2010-06-22T14:50:36.343 回答