【问题标题】:Can and will C# write objects to the pagefile?C# 可以并将对象写入页面文件吗?
【发布时间】:2012-01-27 13:26:31
【问题描述】:

我想知道 C# 是否可以将对象写入页面文件。

我已经知道 .NET 应用程序的虚拟机仅限于允许一个对象仅使用 2 GB 的内存,并且在此之前很久就会耗尽内存 - 即使在 64 位版本的 Windows 上也是如此。

但是,我需要能够加载大量字符串(不是 1 个大字符串,而是许多小字符串),并且想知道是否可以加载它们并将它们写入交换空间,直到再次需要它们(不幸的是,我无法阻止所有字符串的加载,因为它是由调用我正在处理的代码的应用程序强制执行的)。

为了对其进行原型设计,我尝试查看以下程序是否也会耗尽内存(它会),即使它没有尝试分配一个巨大的字符串:

public static void Main()
{
        ICollection<StringBuilder> builders = new LinkedList<StringBuilder>();
        double used_ram = 2*1024*1024*1024L;
        int blocksize = 12800000;
        int blocks = (int) (used_ram/blocksize);
        for (int i = 1; i < blocks ; i++)
        {
            StringBuilder sb = new StringBuilder(blocksize/2);
            builders.Add(sb);
        }
        Console.ReadLine();
}

我希望将字符串写入交换空间,并想知道是否有任何方法可以强制应用程序这样做。

编辑:将交换文件的使用更改为页面文件(感谢您的澄清)。

好吧,为了加强我的问题:如果运行时的唯一限制是 ONE 对象不能分配超过 2 gb 的内存 - 为什么上面的代码内存不足 - 因为列表超过了 2 gb通过持有对所有字符串生成器的引用来记忆?

【问题讨论】:

  • “写入交换”不是应用程序所做的事情,而是操作系统对应用程序所做的事情。如果您的应用/环境仅限于 2G 地址空间,那么“交换”的数量不会增加。
  • 不幸的是,这正是我所期望的——我认为我真的应该研究内存管理的基础知识才能真正掌握所有这些概念。那么有没有办法让运行时分配更多的空间呢?然后我可能不得不将字符串写入文件或存储它们直到需要它们的东西。
  • 交换在 70 年代过时了。如今,虚拟内存系统进行“分页”。在 Windows 中,虚拟内存被分页到“页面文件”。
  • 这有点过早优化的味道
  • @Gjallar - 还请了解您将使用的平台的正确术语。如果我没记错的话,.Net 应用程序可以使用超过 2GB 的内存。那你到底在问什么?

标签: c# memory-management out-of-memory


【解决方案1】:

简短回答:不,你不能。

使用交换不是应用程序做的事情:操作系统的内存管理系统负责。

如果您需要一次在您的进程中加载​​超过 2GB 的数据(而不是根据需要从磁盘中检索每个块的数据),那么您有一个严重的设计问题。


编辑: 由于您已经在使用 64 位操作系统,因此请确保您正在为 x64 平台(或 AnyCPU)编译应用程序,并且您的应用程序没有使用 WOW64 作为 32 位进程运行。

【讨论】:

  • 我会说这真的取决于一个正在编写的应用程序。在许多情况下,这可能是设计问题,但有时实际需要将大量数据加载到内存中。
  • 好吧,我无法真正讨论系统的设计,因为我对团队还很陌生,并且仍在努力掌握系统 - 但这是我被告知要解决的第一个问题看看,所以我猜重新设计有点超出我的授权级别。
  • @Kibbee 我同意某些应用程序确实需要加载超过 2GB 的数据。但在 OP(许多小字符串)的这种特殊情况下,我真的认为这是一个糟糕的设计。
  • @Gjallar:那么你可以迁移到 64 位(提供更大的可寻址内存空间),然后向你的老板要 16GB 或 RAM ;-)
  • @Gjallar 查看更新的答案,因为您已经在使用 64 位操作系统
【解决方案2】:

我认为你的问题相当于:

32 位 .NET 应用程序能否寻址超过 2GB 的内存。

是的,可以通过调整分配给用户应用程序和操作系统的内存之间的分配来增加应用程序可以处理的内存量,但我不建议在大多数情况下这样做,因为它可能会导致微妙而不是那么O / S功能的微妙问题,例如网络。有关/3GB/USERVA 开关的详细信息,请参阅this article。这将使您的应用程序能够处理 3GB(减去开销)而不是 2GB 的内存。

您可以使用的工具有:

  • 切换到 64 位 .NET。
  • 使用内存映射文件。
  • 编写自己的分页系统。
  • 使用一些后备存储,例如文件系统、数据库。

【讨论】:

    【解决方案3】:

    您可以利用所有 Windows 内存管理功能并分配系统允许的尽可能多的内存,但是您正在做的事情需要某种类型的刷新到磁盘系统。即使您可以让窗口分配那么大的对象,您的性能也会很糟糕。有许多开箱即用的系统(称为数据库)允许您将大量数据放入其中并以很短的顺序访问它们。

    【讨论】:

    • 是的,我已经在考虑类似的事情 - 我只是想知道为什么当我自己分配的所有对象都低于每个对象 2 gb 的限制时系统内存不足好吧(这就是为什么我也发布了这个小例子 - 我认为我没有在问题中说得足够清楚 - 抱歉)。
    • 由于操作系统管理内存的方式而耗尽。即使在最佳条件下,2gb 也是一个非常大的内存块,无论你做什么它都会被分页。它只是不是您可以控制的过程
    【解决方案4】:

    你可能做错了什么。我编写了使用超过 2 GB 内存的 .net 应用程序。如果您正在运行 64 位窗口,那么您的应用程序没有理由不能使用更多的内存。

    【讨论】:

    • 好吧,我猜我的小例子内存不足,因为 List 保留了对所有字符串生成器的引用?
    • 我认为这不是问题所在。根据我的计算,你只有大约 167 个块。在链接列表中存储这么多条目不应该产生太多问题。它不存储字符串构建器的副本,只是对它们的引用。如果您有可用的分析器,您应该使用它来查看所有内存的去向。
    【解决方案5】:

    我建议您应该编写自己的缓存类。举个例子看看here

    【讨论】:

      【解决方案6】:

      我认为与您在 .Net 应用程序级别上的方法最接近的是MemoryMappedFile

      但这意味着应用程序不会尝试一次性获取所有字符串。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-12-02
        • 2010-09-27
        • 1970-01-01
        • 2011-01-11
        • 2023-03-06
        • 2018-03-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多