值类型相对于引用类型的优势?

发布于 2025-01-07 11:31:25 字数 394 浏览 1 评论 0原文

由于值类型的新实例每次作为参数传递时都会创建,我开始考虑使用 refout 关键字可以显着提高性能的场景。

一段时间后,我突然意识到,虽然我看到了使用值类型的缺陷,但我不知道有任何优点。
所以我的问题相当直接 - 拥有值类型的目的是什么?通过复制一个结构而不是仅仅创建一个新的引用,我们能得到什么?

在我看来,像 Java 那样只拥有引用类型会容易得多。

编辑:为了澄清这一点,我不是指小于 8 字节(引用的最大大小)的值类型,而是指 8 字节或更多的值类型。

例如 - 包含四个 int 值的 Rectangle 结构。

Seeing as new instances of value types are created every time they are passed as arguments, I started thinking about scenarios where using the ref or out keywords can show a substantial performance improvement.

After a while it hit me that while I see the deficit of using value types I didn't know of any advantages.
So my question is rather straight forward - what is the purpose of having value types? what do we gain by copying a structure instead of just creating a new reference to it?

It seems to me that it would be a lot easier to only have reference types like in Java.

Edit: Just to clear this up, I am not referring to value types smaller than 8 bytes (max size of a reference), but rather value types that are 8 bytes or more.

For example - the Rectangle struct that contains four int values.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

开始看清了 2025-01-14 11:31:25
  • 一字节值类型的实例占用一个字节。引用类型占用引用加上同步块和虚函数表的空间,并且...

  • 要复制引用,请复制四(或八)字节引用。要复制四字节整数,请复制四字节整数。复制小值类型并不比复制引用更昂贵。

  • 垃圾收集器根本不需要检查不包含引用的值类型。每个引用都必须由垃圾收集器跟踪。

  • An instance of a one-byte value type takes up one byte. A reference type takes up the space for the reference plus the sync block and the virtual function table and ...

  • To copy a reference, you copy a four (or eight) byte reference. To copy a four-byte integer, you copy a four byte integer. Copying small value types is no more expensive than copying references.

  • Value types that contain no references need not be examined by the garbage collector at all. Every reference must be tracked by the garbage collector.

巴黎夜雨 2025-01-14 11:31:25

“创建参考”不是问题。这只是 32/64 位的副本。创建对象是昂贵的。实际上创建对象很便宜,但收集它则不然。

当值类型很小并且经常被丢弃时,它们对性能有好处。它们可以非常有效地用于大型阵列。结构体没有对象头。还有很多其他性能差异。

编辑:Eric Lippert 在评论中提出了一个很好的例子:“如果它们是值类型,那么一百万字节的数组会占用多少字节?如果它们是引用类型,它会占用多少字节?”

我会回答:如果结构打包设置为 1,这样的数组将占用 100 万个 16 字节(在 32 位系统上)。使用引用类型将需要:

array, object header: 12
array, length: 4
array, data: 4*(1 million) = 4m
1 million objects, headers = 12 * (1 million)
1 million objects, data padded to 4 bytes: 4 * (1 million)

这就是为什么在大型数组中使用值类型是一个好主意。

"Creating a reference" is not the problem. This is just a copy of 32/64 bits. Creating the object is what is costly. Actually creating the object is cheap but collecting it isn't.

Value types are good for performance when they are small and discarded often. They can be used in huge arrays very efficiently. A struct has no object header. There are a lot of other performance differences.

Edit: Eric Lippert posed a great example in the comments: "How many bytes does an array of one million bytes take up if they are value types? How many does it take up if they are reference types?"

I will answer: If struct packing is set to 1 such an array will take 1 million and 16 bytes (on 32 bit system). Using reference types it will take:

array, object header: 12
array, length: 4
array, data: 4*(1 million) = 4m
1 million objects, headers = 12 * (1 million)
1 million objects, data padded to 4 bytes: 4 * (1 million)

And that is why using value types in large arrays can be a good idea.

静谧 2025-01-14 11:31:25

值类型通常比引用类型具有更高的性能:

  • 引用类型在取消引用时会花费额外的内存用于引用和性能

  • 值类型不会不需要额外的垃圾收集。它与其所在的实例一起被垃圾收集。方法中的局部变量在方法离开时被清理。

  • 值类型数组与缓存结合起来非常高效。 (将整数数组与Integer 类型的实例数组进行比较)

Value types are usually more performant than reference types:

  • A reference type costs extra memory for the reference and performance when dereferencing

  • A value type does not need extra garbage collection. It gets garbage collected together with the instance it lives in. Local variables in methods get cleaned up upon method leave.

  • Value type arrays are efficient in combination with caches. (Think of an array of ints compared with an array of instances of type Integer)

无敌元气妹 2025-01-14 11:31:25

如果您的数据很小(<16 字节)、您有很多实例和/或您经常操作它们,尤其是传递给函数,那么增益是可见的。这是因为与创建小值类型实例相比,创建对象相对昂贵。正如其他人指出的那样,物品需要收集,这甚至更加昂贵。另外,非常小的值类型比它们的引用类型等价物占用更少的内存。

.NET 中非原始值类型的示例是点结构 (System.Drawing)。

The gain is visible if your data is small (<16 bytes), you have lots of instances and/or you manipulate them a lot, especially passing to functions. This is because creating an object is relatively expensive compared to creating a small value type instance. And as someone else pointed out, objects need to be collected and that is even more expensive. Plus, very small value types take less memory than their reference type equivalents.

Example of non-primitive value type in .NET is Point structure (System.Drawing).

尘世孤行 2025-01-14 11:31:25

每个变量都有一个生命周期。但并不是每个变量都需要灵活性,以便变量能够高性能但不在堆中管理。

值类型(结构)包含在堆栈中分配的数据或在结构中内联分配的数据。引用类型(Class)存储对值的内存地址的引用,并在堆上分配。

拥有值类型的目的是什么?
值类型处理简单数据相当高效,(应该用来表示不可变类型来表示值)

值类型对象不能分配在垃圾回收堆上,并且表示对象的变量不包含指向对象的指针;变量包含对象本身。

通过复制结构而不是仅仅创建对其的新引用,我们可以获得什么?

如果复制结构体,C# 会创建该对象的新副本,并将该对象的副本分配给单独的结构体实例。但是,如果复制类,C# 会创建该对象的引用的新副本,并将该引用的副本分配给单独的类实例。结构不能有析构函数,但类可以有析构函数。

Every variable has a lifecycle. but not every variable need the flexibility for your variable to perform high but not managed in heap.

Value types (Struct) contain their data allocate in stack or allocated in-line in a structure. Reference types (Class) store a reference to the value's memory address, and are allocated on the heap.

what is the purpose of having value types?
Value types are quite efficient to handle simple data, (It should be use to represent immutable types to represent value)

Value type objects cannot be allocated on the garbage-collected heap, and the variable representing the object does not contain a pointer to an object; the variable contains the object itself.

what do we gain by copying a structure instead of just creating a new reference to it?

If you copy a struct, C# creates a new copy of the object and assigns the copy of the object to a separate struct instance. However, if you copy a class, C# creates a new copy of the reference to the object and assigns the copy of the reference to the separate class instance. Structs can't have destructors, but classes can have destructors.

沫尐诺 2025-01-14 11:31:25

Rectangle 这样的值类型的一个主要优点是,如果有 n 个 Rectangle 类型的存储位置,就可以确定有 n 个存储位置。 >n 个矩形类型的不同实例。如果有一个 Rectangle 类型的数组 MyArray,长度至少为 2,则像 MyArray[0] = MyArray[1] 这样的语句将将 MyArray[1] 的字段复制到 MyArray[0] 的字段中,但它们将继续引用不同的 Rectangle 实例。如果随后执行语句行 MyArray[0].X += 4,它将修改一个实例的字段 X,而不修改 X任何其他数组槽或 Rectangle 实例的值。顺便说一下,请注意,创建数组会立即用可写的 Rectangle 实例填充它。

想象一下,如果Rectangle是一个可变的类类型。创建一个可变 Rectangle 实例数组需要首先对数组进行标注,然后为数组中的每个元素分配一个新的 Rectangle 实例。如果想要将一个矩形实例的值复制到另一个矩形实例,则必须说出类似 MyArray[0].CopyValuesFrom(MyArray[1]) 的内容 [当然,如果 < code>MyArray[0] 尚未填充对新实例的引用)。如果不小心说出 MyArray[0] = MyArray[1],则写入 MyArray[0].X 也会影响 MyArray[1]。 X。讨厌的东西。

需要注意的是,C# 和 vb.net 中的某些地方编译器会隐式复制值类型,然后像原始值一样对副本进行操作。这是一个非常不幸的语言设计,并促使一些人提出了值类型应该是不可变的命题(因为大多数涉及隐式复制的情况只会导致可变值类型的问题)。当编译器非常不擅长警告语义可疑的副本会产生破坏行为的情况时,这样的概念可能是合理的。不过,今天它应该被认为已经过时了,因为任何像样的现代编译器都会在大多数情况下标记错误,在这些情况下,隐式复制会产生破坏语义,包括结构仅通过构造函数、属性设置器或对公共可变字段的外部赋值进行变异的所有情况。像 MyArray[0].X += 5 这样的语句比 MyArray[0] = new Rectangle(MyArray[0].X + 5, MyArray[0].Y) 更具可读性, MyArray[0].Width, MyArray[0].Height)

One major advantage of value types like Rectangle is that if one has n storage locations of type Rectangle, one can be certain that one has n distinct instances of type Rectangle. If one has an array MyArray of type Rectangle, of length at least two, a statement like MyArray[0] = MyArray[1] will copy the fields of MyArray[1] into those of MyArray[0], but they will continue to refer to distinct Rectangle instances. If one then performs a statement line MyArray[0].X += 4 that will modify field X of one instance, without modifying the X value of any other array slot or Rectangle instance. Note, by the way, that creating the array instantly populates it with writable Rectangle instances.

Imagine if Rectangle were a mutable class type. Creating an array of mutable Rectangle instances would require that one first dimension the array, and then assign to each element in the array a new Rectangle instance. If one wanted to copy the value of one rectangle instance to another, one would have to say something like MyArray[0].CopyValuesFrom(MyArray[1]) [which would, of course, fail if MyArray[0] had not been populated with a reference to a new instance). If one were to accidentally say MyArray[0] = MyArray[1], then writing to MyArray[0].X would also affect MyArray[1].X. Nasty stuff.

It's important to note that there are a few places in C# and vb.net where the compiler will implicitly copy a value type and then act upon a copy as though it was the original. This is a really unfortunate language design, and has prompted some people to put forth the proposition that value types should be immutable (since most situations involving implicit copying only cause problems with mutable value types). Back when compilers were very bad at warning of cases where semantically-dubious copies would yield broken behavior, such a notion might have been reasonable. It should be considered obsolete today, though, given that any decent modern compiler will flag errors in most scenarios where implicit copying would yield broken semantics, including all scenarios where structs are only mutated via constructors, property setters, or external assignments to public mutable fields. A statement like MyArray[0].X += 5 is far more readable than MyArray[0] = new Rectangle(MyArray[0].X + 5, MyArray[0].Y, MyArray[0].Width, MyArray[0].Height).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文