数组大小调整会触发垃圾回收吗?

9
我查看了 Array.Resize() 的实现方式并注意到它会创建一个新的数组并返回。我希望在游戏过程中尽量避免分配内存,因此需要避免创建任何新的引用类型。调整数组大小是否会触发先前数组的垃圾回收?我正在创建自己的 2D 数组调整器,但它基本上和 .NET 的 Resize() 方法一样。
如果新数组比以前的小,但多余的对象已经被放回到通用对象池中,这是否会调用垃圾回收?
在我的游戏循环中将不断创建数组,所以我需要尽可能地提高效率。我正在尝试创建类似于数组池的东西,以便不需要在游戏中不断地创建它们。然而,如果调整大小方法也是如此,那么与其使用池,倒不如只实例化一个新数组。
感谢您的帮助。

也许你可以使用 List<T>,它基本上是一个自动调整大小的数组,我猜当你缩小它时,并不会立即减少数组的大小...嗯,我得检查一下... - digEmAll
3
List<T> 内部使用 T[],但会为您执行调整大小操作。换句话说:它会创建新实例。 - Brian Rasmussen
谢谢建议。我想到了一个列表套列表(因为我正在使用二维数组),但对于我的游戏来说,这样会稍微更加复杂。 - keyboardP
你能解释一下为什么你想要没有内存分配吗? - Eric Lippert
当然,这可能只是微小的优化,但我知道当垃圾收集器在手机上运行时,它肯定会对电池造成不友好影响。 - keyboardP
显示剩余2条评论
4个回答

13

Array.Resize实际上不会改变原始数组-任何仍引用它的人都可以像以前一样使用它。因此,没有可优化性。在我看来,这是一个命名不佳的方法 :(

文档中得知:

该方法分配了一个具有指定大小的新数组,在新数组中从旧数组中复制元素,然后用新数组替换旧数组。

因此,它不会重用原始内存或类似的任何内容。它只是创建了一个具有不同大小的浅表副本。


这是一个很好的观点。最好按值接受原始值并返回新值。在这种情况下,整个按引用传递可能会让初级程序员感到困惑。 - Brian Gideon
我在反编译器中查看这个方法时感到不舒服,因为我看到了一个新的数组被创建。 我想我将不得不在设计方面做出妥协,并进行一些性能测试。 感谢您的回复! - keyboardP
+1 提醒我们,即使 GC 堆在现有数组上方有相邻的未分配“空闲”空间可用,其他句柄持有者的可能性语义上排除了更改现有数组大小的可能性。这意味着,如果 GC 能够证明提交的句柄是最后/唯一的引用,则 Resize 可以进行 原地 优化。然而,尽管不太严谨,但此时这样做将是对依赖于原始与调整大小实例具有不同引用标识的假设的现有应用程序的 破坏性更改 - Glenn Slayden

2

是的,使用Array.Resize会导致分配一个新的数组,并最终回收旧的数组(除非还有其他地方对其的引用)。

在某些情况下,更低级别的数组调整器可能会进行一些轻微的优化(例如当数组变小或者恰好在数组之后有可用的内存时),但.NET的实现并没有这样做。


1

隐式是的。

显式不行。


1
任何分配最终都会在没有更多引用存在时被垃圾回收器清理,所以是的。
如果你想避免调整数组大小,最好的方法就是预先分配足够大的空间,以避免完全重新分配。在这种情况下,您可以使用一个带有构造函数中指定的初始容量的集合类,例如List。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接