【问题标题】:When does the zero-fill operation take place for an array in C#?C#中的数组何时进行零填充操作?
【发布时间】:2012-02-03 09:56:36
【问题描述】:

在 C# 中考虑这个:

int[] a = new int[1024];

所有整数都将设置为 0。传统上,这是通过高度优化的零填充操作完成的(例如 memset)。然而,由于这个数组是由 CLR 分配的,我可以想到一个非常简单的优化; CLR 可以维护一个归零的内存区域,以便在我们请求内存时跳过这个零填充。

现在,CLR 会执行这样的优化吗? (我目前使用的是 .NET 4.0)

【问题讨论】:

  • 你为什么要关心?当然,除了学术兴趣。
  • 我恰好是从 C++ 世界中成长起来的,那里的程序员实际上关心底层代码。 (并且......在 CPU 密集型算法中处理巨大的内存块,不必要的归零可能会成为瓶颈。知道何时发生归零是有意义的。)
  • '你为什么要关心?' - 让我想起了'Why you readin' for?'

标签: c# arrays performance initialization


【解决方案1】:

这在低得多的级别上运行。 Windows 使低优先级内核线程保持活动状态,其唯一工作是将内存页面的内容归零。称为“零页线程”。这些页面保存在一个池中,可供任何为保留但未提交的页面生成页面错误的进程使用。 Windows 中的任何代码都可以从中受益,而不仅仅是托管代码。目的是为了安全,而不是将映射内存页面的 RAM 内容归零会允许程序监视另一个进程的内存。

这不会发生在您的阵列上,它太小了。它在 gen #0 堆中分配,该堆将始终具有映射页面。然而,大数组在大对象堆中分配,大是 85,000 字节,双精度数组为 8000 字节。 LOH 分配可以利用将页面预初始化为零的优势。很难说它是否真的有效,它的源代码在任何地方都不可用。我会说它可能会考虑它节省的 CPU 周期数。

【讨论】:

    【解决方案2】:

    CLR 只分配一个bit more memory 而不是托管堆消耗,然后如果它用完托管堆的未分配内存,它将向操作系统请求更多内存。仅当您的进程工作集已经很大并且您有很多未使用的内存被垃圾收集时,对内存进行预置零才会发挥作用。然后,此内存可从托管堆中分配。 如果您的应用程序是这种情况,您应该考虑重用数组而不是丢弃它以避免在托管堆上重新分配。

    【讨论】:

    • 不,它不会调用结构的构造函数。结构没有无参数的实例构造函数(规范中的 11.3.8)。通过将所有值类型字段设置为其默认值来初始化结构。此外,使用创建表达式(即初始化程序)创建的数组元素始终初始化为其默认值。
    • @MikeCowan 你是对的,我将它与包含构造的 ctor 混合在一起,并强制编译器手动初始化所​​有字段。从我的答案中删除了那部分。
    【解决方案3】:

    您是否查看过为此代码生成的 IL?可能会为相关呼叫生成对newarr 的呼叫。根据 ECMA-355,newarr 创建一个新的从零开始的一维数组,并将数组的元素初始化为适当类型的 0。在这种情况下,由于它是 int 的数组,因此元素将在创建时初始化为 0。

    【讨论】:

      猜你喜欢
      • 2021-11-16
      • 2020-03-21
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 2012-09-09
      • 2016-11-06
      • 2021-11-25
      • 1970-01-01
      相关资源
      最近更新 更多