【问题标题】:Does array resizing invoke the GC?数组调整大小是否会调用 GC?
【发布时间】:2010-09-02 17:34:39
【问题描述】:

我查看了 Array.Resize() 的实现,并注意到创建并返回了一个新数组。我的目标是在游戏过程中实现零内存分配,因此我需要避免创建任何新的引用类型。调整数组大小会触发前一个数组上的垃圾收集器吗?我正在创建自己的 2D 数组调整器,但它的功能本质上与 .NET Resize() 方法相同。

如果新数组比前一个数组小,但多余的对象已经放回通用对象池,这会调用 GC 吗?

在我的游戏循环中会不断创建数组,因此我需要尝试使其尽可能高效。我正在尝试创建一个 array pool 这样,因此无需继续在游戏中创建它们。但是,如果 resize 方法做同样的事情,那么不只是实例化一个新数组而不是拥有池是没有意义的。

感谢您的帮助

【问题讨论】:

  • 也许你可以使用List<T>,它基本上是一个自动调整大小的数组,我想当你缩小它时,它不会立即缩小数组......嗯,我必须检查......
  • @digEmAll: List<T> 在内部使用 T[] 但会为您调整大小。换句话说:它将创建新实例。
  • 感谢您的建议。我想到了一个列表(因为我使用的是 2D 数组),但它对我的游戏来说稍微复杂一些。
  • @Brian:当然可以,但是 IIRC 不会在每次插入/删除时调整大小,但以某种方式避免过多的调整大小,即新实例。 (每次插入时它的大小加倍,需要比可用空间更多的空间或类似的东西......)
  • 你能解释一下为什么你不想分配内存吗?

标签: c# .net arrays garbage-collection xna


【解决方案1】:

Array.Resize 实际上并没有改变原始数组 - 任何仍然引用它的人都可以像以前一样使用它。因此不可能进行优化。坦率地说,这是一个名字很糟糕的方法,IMO :(

来自docs

此方法分配一个新数组 指定大小,复制元素 从旧阵列到新阵列,以及 然后用 新的。

所以不,它不会重用原始内存或类似的东西。它只是创建一个不同大小的浅拷贝。

【讨论】:

  • 这很好。最好按价值接受原件并返回新的。在这种情况下,这里的整个引用传递真的会让初级程序员感到困惑。
  • 我正在使用 Reflector 中的方法,但当我看到正在创建一个新数组时,它并没有正确放置。我想我将不得不在设计上做出妥协,并进行一些性能测试。感谢您的回复!
  • +1 提醒我们,即使 GC 堆在现有数组的正上方有相邻的未分配“空闲”空间可用,其他句柄持有者的可能性在语义上排除了更改现有数组的大小。这意味着Resize可以原位优化iffGC可以证明提交的句柄是最后/唯一的引用。然而,尽管不那么严格不正确,但此时这样做对于现有应用程序来说将是一个重大变化,这些应用程序依赖于原始与调整大小的实例具有不同引用标识的假设。
【解决方案2】:

是的,使用Array.Resize 会导致分配一个新数组并最终收集旧数组(除非某处仍有对其的引用)。

在某些情况下(例如,当数组变小或恰好在数组之后有可用内存时),更底层的数组调整器可能会做一些小的优化,但 .NET 的实现不会这样做那个。

【讨论】:

    【解决方案3】:

    暗示是的。

    明确没有。

    【讨论】:

      【解决方案4】:

      当没有更多引用存在时,GC 最终会清理任何分配,所以是的。

      如果您想避免调整数组大小,您可以做的最好的事情是预先分配足够大的大小以避免重新分配。在这种情况下,您不妨只使用一个在构造函数中指定初始容量的集合类,例如 List。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-10
        • 2011-01-15
        • 1970-01-01
        • 1970-01-01
        • 2018-09-14
        • 2017-08-24
        相关资源
        最近更新 更多