質問

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.

役に立ちましたか?

解決

  • 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.

他のヒント

"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.

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)

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).

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.

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).

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top