gpt4 book ai didi

c# - .NET中通用和非通用集合之间的内存使用差异

转载 作者:太空狗 更新时间:2023-10-29 22:06:04 26 4
gpt4 key购买 nike

如今,我在.NET中阅读了有关集合的信息。众所周知,使用泛型集合优于非泛型:它们是类型安全的,没有强制转换,也没有装箱/拆箱。这就是通用集合具有性能优势的原因。

如果我们认为非泛型集合将每个成员存储为object,那么我们可以认为泛型还具有内存优势。但是,我没有找到有关内存使用差异的任何信息。

任何人都可以澄清这一点吗?

最佳答案

If we consider that non-generic collections store every member as object, then we can think that generics have also memory advantage. However, I didn't found any information about memory usage difference. Can anyone clarify about the point?



当然。让我们考虑一个包含 ArrayListintList<int>。假设每个列表中有1000个 int

在这两种类型中,集合类型都是数组的薄包装-因此名称为 ArrayList。在 ArrayList的情况下,存在一个底层 object[],其中包含至少1000个装箱的整数。如果是 List<int>,则存在一个底层 int[],其中至少包含1000 int

为什么我说“至少”?因为两者都使用双倍充值策略。如果在创建集合时设置集合的容量,则它会为很多东西分配足够的空间。如果您不这样做,则该集合必须猜测,如果它猜错了并且您需要更多的容量,则它的容量将增加一倍。因此,最好的情况是,我们的集合数组大小恰到好处。最坏的情况是,它们的大小可能是所需大小的两倍。数组中可能有2000个对象或2000个int的空间。

但是,为简单起见,我们假设我们很幸运,每一个中大约有1000个。

首先,仅阵列的内存负担是多少? object[1000]在32位系统上占用4000字节,在64位系统上占用8000字节,仅用于指针大小的引用。无论如何, int[1000]占用4000个字节。 (数组记账还占用了一些额外的字节,但是与边际成本相比,这些成本很小。)

因此,我们已经看到,非通用解决方案可能只为阵列消耗两倍的内存。数组的内容呢?

好吧,关于值类型的事情是它们存储在自己的变量中。除了用于存储1000个整数的4000字节之外,没有其他空间。他们被打包到阵列中。因此,对于一般情况,附加成本为零。

对于 object[]情况,数组的每个成员都是一个引用,并且该引用引用一个对象;在这种情况下,是装箱的整数。装箱整数的大小是多少?

未装箱的值类型不需要存储有关其类型的任何信息,因为其类型由其所在的存储类型决定,而运行时是已知的。装箱的值类型需要在框中将事物的类型存储在某处,这会占用空间。事实证明,在32位.NET中,对象的簿记开销为8字节,在64位系统上为16。那只是开销。我们当然需要4个字节的int。但是,等等,情况变得更糟:在64位系统上,该框必须与8字节边界对齐,因此在64位系统上我们需要另外4字节的填充。

全部添加:在64位和32位系统上,我们的 int[]大约需要4KB。我们的 object[]包含1000个整数,在32位系统上大约需要16KB,在64位系统上大约需要32K。因此,对于非一般情况, int[]object[]的内存效率相比要差4或8倍。

但是,等等,情况变得更糟。只是大小而已。那访问时间呢?

要从整数数组访问整数,运行时必须:
  • 验证该数组有效
  • 验证索引有效
  • 从给定索引
  • 的变量中获取值

    要从装箱整数数组访问整数,运行时必须:
  • 验证该数组有效
  • 验证索引有效
  • 从给定索引
  • 的变量中获取引用
  • 验证引用不为空
  • 验证引用是否为盒装整数
  • 从方框
  • 中提取整数

    这需要更多步骤,因此需要更长的时间。

    但是请稍等片刻。

    现代处理器使用芯片本身的缓存来避免返回主内存。由1000个纯整数组成的数组很有可能最终在缓存中结束,因此快速连续访问数组的第一个,第二个,第三个等成员都从同一缓存行中拉出。这太快了。但是,装箱的整数可以遍及整个堆,这会增加高速缓存未命中的次数,从而进一步大大降低访问速度。

    希望这足以阐明您对拳击罚款的理解。

    非盒装类型呢?字符串数组列表和 List<string>之间有显着差异吗?

    这里的损失要小得多,因为 object[]string[]具有相似的性能特征和内存布局。在这种情况下,唯一的额外惩罚是(1)在运行时才捕获您的错误;(2)使代码更难以阅读和编辑;(3)进行运行时类型检查的轻微惩罚。

    关于c# - .NET中通用和非通用集合之间的内存使用差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47182453/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com