I didn't understand a few things before, but I simply used the null type and I also knew how to use it. As for why, I am not quite clear. I learned a lot by sorting out this article, it may be helpful for future code optimization.
The focus of this article is: the value type stores its value directly, and the reference type stores Reference to the value. The value type exists on the stack, and the reference type is stored on the managed stack, the conversion of the value type to the reference type is called packing, and the conversion of the reference type to the value type is called unpacking.
This sentence is very simple in summary, but it is not so easy to understand. For me, right.
C # value-type data is stored directly in the memory allocated to it, while C # reference type only contains pointers pointing to the location of the stored data.
C # value type. We can classify it into three types:
Category 1: Basic Data Type (except string type): integer, floating point, decimal, and Boolean.
Integer types include sbyte, byte, char, short, ushort, int, uint, long, And ulong;
Float types include float and double;
Decimal;
Boolean is the bool type.
Class 2: Structure Type: struct type
Category 3: Enumeration type: enum type
C # There are five types of reference: class, interface, delegate, object, and string.
The above section describes how to distinguish between C # value types and C # reference types. Data of all value types cannot be null. After the declaration, the initial value must be assigned; the reference type can be null.
But here we can take a lookNull type
An empty type can represent all values of the basic type, and a null value. An empty type can be declared in either of the following ways:
System.Nullable<T>? variable
T is the basic type that can be empty. T can be any value type including struct, but cannot be a reference type.
1. After adding a question mark to the value type, this type can be empty, such as int? I = null;
? d = <> e = ;
2. When the null type is used together with the one-dimensional or binary operator, if one of the operands is null, the result is null;
3. When the comparison can be empty, as long as one operand is null, the comparison result is false.
The value type is different from the reference type when assigning values (or copying. When values are assigned, values are directly copied to the new object, while the reference type is only a reference of the Copied object.
Finally,The value type exists on the stack, and the reference type is stored on the managed stack.Next let's take a look at the stack and stack.
StackStack,HeapIt refers to the managed heap. It should be called in C.
1. stack:Storage value type in the stack.
The stack is actually filled up and down, that is, the high memory address points to the low memory address.
The stack works by allocating memory variables first and then releasing them (Advanced and then outgoing ). The variables in the stack are released from the bottom up, which ensures that the rules that come first in the stack do not conflict with the life cycle of the variables!
The stack performance is very high, but it is not flexible for all variables, and the lifecycle of variables must be nested.
We usually want to use a method to allocate memory to store data, and the data can still be used for a long time after the method exits.In this case, the heap (managed heap) is used)!
2. How C # stacks work
Windwos uses a virtual addressing system to map available memory addresses of programs to actual addresses in Hardware Memory, each process on a 32-bit processor can use 4 GB of memory-no matter how much hard disk space the computer has (on a 64-bit processor, this number is larger ). The 4 GB memory contains all parts of the program-executable code, loaded DLL, and all variables. The 4 GB memory is called virtual memory.
Each 4 GB storage unit starts from 0 and goes up. The value of the storage space to access the memory. You need to provide the number of the storage unit. In advanced languages, the compiler converts a name that we can understand into a memory address that the processor can understand.
In the virtual memory of a process, a region is called a stack to store value types.. In addition, when a method is called, all parameters passed to the method through stack replication are used.
Let's take a look at the following small example:
After a is declared, B is declared in the internal code block, and then the internal code block is terminated, B is out of scope, and then a is out of scope. When releasing variables, the order is always the opposite of the order of allocating memory to them, and the latter is the way the stack works.
Stack is filled down, that isFill in from high address to low address. When data is imported into the stack, the stack pointer is adjusted accordingly, pointing to the next free space. Let's give an example.
If the stack pointer is 2000, The next free space is 1999. The following code tells the compiler that it needs some storage units to store an integer and a double-precision floating point number.
c = d=
Both are value types, which are naturally stored in the stack. After the c value is declared as 2, c enters the scope. Int type requires 4 bytes, and c is stored in 1996 ~ On the 1999. In this case, the stack pointer is reduced by 4, pointing to the end of the new space used by 1996, and the next free space is 1995. After the next row declares that d is assigned a value of 3.5, double occupies 8 bytes, so it is stored in 1988 ~ On 1995, stack pointer minus 8.
When d is out of scope, the computer will know that this variable is no longer needed. The lifetime of a variable is always nested. When d is in the scope, no matter what happens, the stack pointer can always point to the space where d is stored. When the d variable is deleted, the stack pointer increments by 8 and now points to the space used by d, where curly braces are closed. Then c is out of scope, and the stack pointer increments by 4.
If a new variable is added, the storage unit starting from 1999 will be overwritten.
3. heap (managed heap) Storage reference type.
This heap is not another heap, And the heap in. NET is automatically managed by the garbage collector.
Unlike the stack, the stack is allocated from the bottom up, so free space is on the top of the used space.
4. How the managed heap works
The stack has high performance, but requires that the lifecycle of the variable must be nested (first-in-first-out ). We usually want to use a method to allocate memory to store some data, and the data is still available for a long time after the method exits. This possibility exists when the new operator is used to request space-for example, all reference types. At this time, we need to use the hosting heap.
Managed heap is another region where the process is available 4 GB. We use an example to understand how managed heap works and allocate memory for referenced data types. Suppose we have a Cat class.
Name { ;
Let's take a look at the simplest method below. Of course there are two lines of code. In the first section, we also mentioned http://www.cnblogs.com/aehyok/p/3499822.html.
cat = }
The third line of code declares a Cat reference cat and allocates storage space for this reference on the stack, but this is just a reference, not an actual Cat object. Cat reference contains the address for storing Cat objects-4 bytes are required ~ The address between 4 GB is stored as an integer-So cat reference occupies 4 bytes.
The fourth line of code first allocates memory on the hosting stack to store Cat instances, and then sets the cat variable value to the memory address allocated to the Cat object.
Cat is a reference type, so it is placed in the memory hosting heap. For convenience, assume that the Cat object occupies 32 bytes, including its instance fields and. NET information used to identify and manage its class instances. To locate a storage location that stores new Cat objects in the managed stack ,. NET Runtime Library will search for a continuous unused 32-byte space in the heap, assuming that its starting address is 1000. The four bytes of memory address in the stack are: 1996 to 1999. This should be the case before instantiating cat.
Cat instantiation: after a Cat object is allocated space, the memory changes to the memory address from 1996 to 1999 used by cat in the stack, and then the Cat object is allocated space.
Different from the stack, the memory on the stack is allocated upwards, and all free space is above the used space.
The preceding example shows that the process of referencing a variable is much more complex than that of creating a value variable, and the performance cannot be reduced -. NET Runtime library needs to maintain the heap Information Status. When adding new data to the heap, the information also needs to be updated (this will be mentioned in the heap garbage collection mechanism ). Despite these performance losses, there is also a mechanism that will not be restricted by the stack when allocating memory to variables:
Assign the value of variable e to another variable f of the same type. Both of the referenced variables reference the same object. When the variable f is out of scope, it will be deleted by the stack, but the object referenced by it is still on the stack, because another variable e is referencing this object. The object will be deleted only when its data is no longer referenced by any variable.
5. managed heap garbage collection
Objects that are no longer referenced in the heap will be deleted. If this is the case, over time, the free space on the stack will be dispersed, and it will be difficult to allocate memory to new objects ,. NET Runtime Library must search for the entire heap to find a memory block that is large enough to store the entire new object.
But when the Garbage Collector hosting the heap is running, as long as it releases objects that can be released, it will compress other objects and push them to the top of the heap to form a continuous block. When moving an object, you must update the addresses referenced by all objects, resulting in performance loss. However, when using the managed heap, you only need to read the value of the heap pointer, instead of searching the entire link address list to find a place to place new data.
Therefore, it is much faster to instantiate objects in. NET, because objects are compressed to the same memory area of the heap, and fewer pages are exchanged when accessing objects. Microsoft believes that although the Garbage Collector needs to do some work to modify all object references it moves, resulting in performance degradation, this performance will be compensated.
1. binning converts the value type to the reference type, and unboxing converts the reference type to the value type.
The binning and unboxing functions allow conversion between any value of the value type and the value of the Object type to link the value type with the reference type.
For example, the following code:
Main( val = obj =
This is actually a simple packing process, the process of converting the value type to the reference type.
Main( val = obj = num = (
In the preceding example, int num = (int) obj; is used to unpack the bin.
Note: Only objects that have been packed in boxes can be split.
2. Why packing? (Why convert the value type to the reference type ?)
One of the most common scenarios is to call a method containing parameters of the Object type. This Object can support any type for general purpose. You need to pack a value type (such as Int32.
Another method is to define an element type as an Object to ensure the universality of a non-generic container. Therefore, to add the value type data to the container, You need to pack the data.
3. binning/unboxing internal operations.
Packing:
Assign an object instance to the heap and copy the value to the new object. Step by step.
Step 1: allocate new managed heap memory (size: Value Type instance size plus a method table pointer and a synchronized block index SyncBlockIndex ).
Step 2: copy the instance field of the value type to the newly allocated memory.
Step 3: return the address of the newly allocated object in the managed heap. This address is a reference to the object.
Unpack:
The unpacking process is the opposite of the packing process. Read a piece of code:
a = b = c = ()b;
You must be very careful when disassembling the variable to make sure that there is enough space for storing the value obtained after unpacking. C # int only has 32 bits. If the 64-bit long value is split into int, an InvalidCastExecption exception is generated.
Obviously, from the principle, we can see that during packing, a brand new reference object is generated, which may result in time loss, that is, reduced efficiency.The packing and unpacking operations require additional cpu and memory resources. Therefore, a generic type is introduced after c #2.0 to reduce the consumption of packing and unpacking operations.
4. Non-generic packing and unpacking, and generic
array = ( value
The Code declares an ArrayList object and adds two numbers, 1 and 2 to the ArrayList. Then, use foreach to print the elements in the ArrayList to the console.
During this process, two packing operations and two unpacking operations will occur. When an int type element is added to the ArrayList, when you use foreach to enumerate the int type elements in the ArrayList, The unboxing operation will occur. Convert the object type to the int type and execute the operation on the Console. writeLine, The binning operation is performed twice. This code runs six binning and unboxing operations. If the number of ArrayList elements is large, more operations will be performed for packing and unpacking.
list = List<> ( value
The difference between code and the code in 1 is that the set type uses a generic List instead of an ArrayList. the above code is only available on the Console. the WriteLine () method is used to pack data twice without unpacking.
It can be seen that the generic type can avoid unnecessary performance consumption caused by packing and unpacking. Of course, the benefits of the generic type are not limited to this, and the generic type can also increase the readability of the program, it makes the program easier to be reused, and so on. For the generic type, I will introduce it in detail later.
I learned a lot of things by myself. If I have nothing to do, I will take it out more. Maybe there will be unexpected gains. Continue to cheer!