C# 长度为 1 的数组与单值、性能和内存开销

C# length 1 array versus single value, performance and memory overhead

问题:

使用长度为1的数组而不是直接使用值的性能和内存开销是多少?

private Item[] item = new Item[1];
   vs.
private Item item;

用法:

我有一个抽象基础 class ItemHolder,它由 SingleItemHolder 和 MultipleItemHolder classes 继承。第一个持有一个项目作为主要价值,而另一个持有一个列表。要访问该值,我看到三种可能性:

在基础上添加两个方法class

public abstract Item GetItem();
public abstract Item[] GetItems(int amount);

缺点是 SingleItemHolder 有不必要的方法来获取多个项目,而每个定义只有一个项目。
另一种方法是只实现第二种方法并将单个值作为长度为 1 的数组传递

public override Item[] GetItems()
{
    return new[] { storedItem };
}

或者首先将单个值存储为长度为 1 的数组

private Item[] item = new Item[1];
public override Item[] GetItems()
{
    return item;
}

多件和单件支架的使用频率相同,一般来说使用频率相当高。所讨论的方法很可能在整个游戏世界的每个游戏帧中被调用数十次。因此,我想知道哪个版本最有效,或者更笼统地说,长度为 1 的数组在单个值上的开销有什么不同。

What is the performance and memory overhead of using an array with the length of 1 instead of the value directly?

这完全取决于编译器优化、JiT 编译器和索引访问器修剪今天对该数组的看法。在它的核心,一切都是指针。该进程不关心它是指向函数、单个 int 还是 int 数组的开头。除了跳转到 Indexer 函数和 Indexer 健全性检查之外,应该不会对性能产生影响。甚至可以修剪一个索引器访问,或者至少内联。

理论上可能 优化会看到您的 new int[1] 并决定基本的 int 可以做到。如果仅在运行时定义大小,JiT 甚至可以做到这一点。然而,这不太可能。

如果你需要一个数组,你就需要一个数组。有时为 1 的奇怪情况无需担心。即使大小为 1 的数组在某种程度上很常见,具有基本 int 的路径也将是一种微观优化。它只会落在速度咆哮之下:https://ericlippert.com/2012/12/17/performance-rant/

如果您有两个函数重载 - 一个采用 int 和一个采用 int[] - 你应该只编码出 int[] 版本。链接 int 版本以调用数组版本非常简单。

只是一个简短的说明。在 .NET 世界中,最大的性能问题是可能很容易将应用程序锁定 50-100 毫秒的 GC。从对象或单值数组读取数据时,您可能看不出有什么大的不同。但是如果你需要大量创建这样的对象,你可能会受到惩罚。您一定要避免从 getter 代码创建对象。

我认为这篇文章可能会有所帮助:https://michaelscodingspot.com/avoid-gc-pressure/。还可以考虑使用一些配置文件工具来检查实际花费的时间。我更喜欢使用 MS 提供的 PerfView。开始使用它可能需要一些时间,但您肯定会从结果中获益。