【问题标题】:How are arrays created and accessed如何创建和访问数组
【发布时间】:2011-12-09 06:40:29
【问题描述】:

我理解(虽然不完全是为什么)原始类型(例如 int、float)的实例存储在堆栈中,而不是堆分配的。但是我对原始类型数组的存储和访问方式有点困惑。我有这个问题是因为 System.Array 是一个引用类型。并且引用类型是堆分配的。

int[] integers = {1,2,3,4,5};

这些单独的整数是如何在内存中存储和访问的?

【问题讨论】:

    标签: c# clr


    【解决方案1】:

    基本上,你的“理解”是有缺陷的。值类型值有时存储在堆栈中 - 但不是数组或任何其他基于堆的对象的一部分。不幸的是,有些人选择对存在于堆栈中的值类型做出如此笼统的陈述,这让其他人感到困惑:(

    另外,the stack/heap distinction is an implementation detail...

    有关更多详细信息,请参阅my article on memory,但肯定阅读 Eric Lippert 的博客文章(在上一段中链接)以了解更多哲学考虑。 (阅读他的other posts on value types 了解更多信息。)

    【讨论】:

      【解决方案2】:

      你已经发现了为什么“值类型总是存储在堆栈上”这句话显然是错误的。事实是,所存储对象的类型与其存储位置无关。正确的规则是生命周期短的值存储在短期“堆栈”的存储中,而生命周期长的值存储在长期“堆”的存储中 em>。

      当你这样说时,它实际上是一个重言式。很明显短期的东西是从短期存储中分配的,而长期存在的东西是从长期存储中分配的!不然怎么可能?但是当你这样说的时候,很明显类型是无关紧要的,除非类型给你关于生命周期的提示。

      整数数组的内容可能是长期存在的,因此整数是从长期存储中分配的。 int 类型的局部变量的内容通常是短期的,因此它通常是从短期存储中分配的。

      【讨论】:

      • @Eric:所以分配是基于一些预定义的变量短/长寿命准则?如果结果相反,是否将其重新分配给其他类型的存储(即从堆栈到堆,反之亦然)?
      • @JoanVenge:正确。例如,局部变量通常是短暂的。 (“短命”是指“不会超过需要存储的方法正常返回或抛出的时间。”)但是如果局部变量位于迭代器块中,则它是 lambda 的封闭局部,或者在异步方法中,它可以在方法正常完成后使用。因此,这些本地人被分配到长期商店之外。引用类型的实例可能会存在很长时间,因此它们会长期存储。 对这些实例的引用可能是短暂的!
      • 理论上我们还可以注意到引用类型的实例实际上并没有超过方法的末尾,而是在堆栈上分配它。在实践中,我们实际上并没有执行这种优化。
      • @Eric 那是编译器优化还是 JIT 优化?它与逃逸分析有关吗? (我认为这需要对对象内部的一些深入了解,因为它可以通过多种方式保持自身活力。)
      • @EricLippert 这意味着值和引用类型实例之间唯一的理论区别是它们的数据在原始方法边界之外传递的方式?其他一切都是实施细节,可能会发生变化?
      【解决方案3】:

      数组本身总是一个引用类型,所以它存储在堆上。数组的元素也存储在堆上,但总是在一个连续的内存块中。

      【讨论】:

        【解决方案4】:

        Jeffry Richter 在 2002 年写的 article 非常清楚地解释了这个概念。

        【讨论】:

          猜你喜欢
          • 2011-11-06
          • 1970-01-01
          • 2022-08-20
          • 2011-01-23
          • 1970-01-01
          • 2021-08-17
          • 2017-04-13
          • 2020-05-22
          • 1970-01-01
          相关资源
          最近更新 更多