【问题标题】:What happens when the RAM is over in C#?当 C# 中的 RAM 结束时会发生什么?
【发布时间】:2011-08-25 12:27:46
【问题描述】:

我不是计算机专家,所以让我试着更具体地提出这个问题:

我做一些科学计算,计算有时需要大量内存来存储结果。几天前,我有一个在硬盘上占用 4 GB 的输出文件,但我有这么多的 RAM。所以:

  • 当您运行的程序分配的内存比计算机中的可用内存多时,CLR(或其他什么?)如何处理内存?它会在高清中创建一些交换吗? (我知道这可能会减慢我的程序,但我只对内存问题感兴趣)
  • 它是否依赖于操作系统,比如我是在 linux 上使用 MONO 还是在 Windows 上使用 VS?

提前致谢!

【问题讨论】:

  • 附注,但您可以保存一个 4GB 的文件,而不必将所有 4GB 都存储在内存中。文件流实现通常有一个中间写入缓冲区,当您写入流时,该缓冲区会定期刷新到底层磁盘。
  • 实际上,我试图找出一些方法来处理这个“大文件”问题......我的想法是将输出文件拆分为小文件,比如 100 MB。 Stream 可能有用,但这是另一个问题,感谢您的说明!
  • 只要您使用相当现代的操作系统,我相信操作系统文件系统将允许非常大的文件并在内部处理所有“分块”。一些工具在处理非常大的文件时会遇到问题,但文件本身应该可以正常存储。所有这些都与内存消耗无关,例如,如果您在写入文件时需要保留大量内存用于计算,这只是一个问题。您是否真的遇到了问题,或者这只是考虑可能的问题?
  • 其实这只是一个考虑,伴随着分析那些文件的问题...

标签: c# .net memory-management virtual-memory


【解决方案1】:

我觉得有助于思考的方式是:内存是磁盘空间。 RAM 是一种快速缓存。与其思考“当我的 RAM 用完时,系统会将其交换到磁盘”,我认为“当我有可用的 RAM 时,系统会将我的磁盘内存移入其中”。

这与大多数人的想法相反,但我发现它有帮助。 RAM只是性能优化;您可以分配多少内存的真正限制是可用磁盘空间。

当然比这更复杂。在 32 位操作系统上,每个进程都有一个 20 亿字节的用户地址空间。 (内核地址空间也是如此,但让我们忽略它。)您可以访问的每一页内存,无论是在 RAM 中还是在磁盘上,都必须在该地址空间中。你可以分配超过 20 亿字节,没问题。但是您一次只能寻址 2 GB。如果分配了 10 GB,则至少有 8 GB 不会映射到地址空间。在这种情况下,您必须 取消映射 其他内容,然后将您想要的内容映射到地址空间中才能得到它。

此外,很多东西需要在连续地址空间中。例如,如果您有一个 1MB 的堆栈,那么地址空间中需要有一百万个连续字节可用。

当人们“内存不足”时,他们并没有用完 RAM; RAM 只是磁盘上的快速缓存。而且它们并没有耗尽磁盘空间;有很多这样的。他们几乎总是处于连续地址空间不足以满足需求的情况。

CLR 内存管理器不会为您实现这些花哨的 map-and-unmap 策略;基本上,您将获得 2GB 的地址空间,仅此而已。如果你想做一些花哨的事情,比如内存映射文件,这取决于你自己编写代码来管理内存。

【讨论】:

  • 映射和取消映射听起来很有趣。你能发布一个如何在 C++ 中使用它的链接吗?
  • 当您说“CLR 内存管理器没有为您实现这些花哨的映射和取消映射策略”时,为什么?我从来不用处理这个问题,是不是因为这些不能以通用的、一刀切的方式实现?只是好奇:O
  • @Joan:因为要知道什么可以有效地映射进出是一个非常困难的问题。假设你想在内存中有一个 10GB 的视频文件来编辑它。编辑软件的作者可以知道“好的,文件是这样布局的,所以我们把视频的这么多秒映射到地址空间,把我们现在不编辑的秒解映射”。 CLR 对哪些内存部分可能很快会被访问以及哪些不会被访问没有那种理解。
  • 谢谢埃里克,我明白你的意思了。听起来绝对是个难题。
【解决方案2】:

如果您分配的内存比实际存在的多,是的,将使用交换空间。

如果您分配的内存超出了可寻址范围,则会出现OutOfMemoryException

不确定 Mono,但我猜这取决于运行时并且行为方式几乎相同(物理内存不足会导致交换,分配过多会导致异常)。

【讨论】:

  • 抱歉,您所说的可寻址是什么意思? tks
  • @Girardi:基本上,您的应用要求 6Gb 但您的机器只有 1Gb,您会得到一个OutOfMemoryException
  • @Sergio - 不太正确。 32 位操作系统的地址空间为 2^32 位(大约 4 GB) - 如果您尝试分配的内存超出进程的处理能力,您将收到 OOM 异常。对于 64 位操作系统,这要大得多。如果您在 32 位操作系统上只有 1GB 内存并尝试使用 3GB,则会使用虚拟内存 - 即会发生磁盘交换。
  • @Sergio:不一定是这样。理论上,您可以使用比您的机器实际可用的内存更多的内存。限制是您的操作系统可以使用多少内存。例如,在 32 位版本的 Windows 下,最多 2 GB 的内存可用于用户模式应用程序。除此之外,您的应用程序没有可寻址或可用的内存。在 64 位世界中,这个限制会大大提高。
  • @Oded:因此,如果您尝试处理的内存超出操作系统的处理能力,您将收到此异常,对吗?
【解决方案3】:

运行时只是要求操作系统提供更多内存。操作系统处理将内存的现有内容分页到磁盘,并在必要时进行交换以创建更多可用的物理内存。托管 C#/.NET 程序与常规非托管程序发生的情况相同。

托管应用程序领域的唯一区别是 .NET 运行时会产生一些内存开销,从而限制了应用程序实际可用的内存总量。例如,垃圾收集器需要一些内存空间来完成它的工作。

所以是的,它至少在某种程度上是依赖于操作系统的。然而,大多数现代操作系统的内存管理方法都非常相似。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多