A brief summary of Unity C# data types and memory allocation

C# is a strongly typed language, and every variable must specify a data type.

C# data types are divided into value types, reference types, and pointer types.

Value types include integer, floating point, character, Boolean, enumeration, etc.;
reference types include classes, interfaces, arrays, delegates, strings, etc.

Data Storage - Stack and Heap

Four types of data are mainly placed in the stack and heap: Value Type, Reference Type, Pointer, and Instruction.

The stack is responsible for saving the path of our code execution (or call), and the heap is responsible for saving the path of objects (or data, we will talk a lot about the heap in the following).

Think of a stack as a stack of top-down boxes. Every time a method is called, we record what happens in the application in a box at the top of the stack, and we can only use the box at the top of the stack each time. When the box at the top of our stack has been used, or the method has finished executing, we will discard the box and continue using the new box at the top of the stack.

The working principle of the heap is similar, but most of the time the heap is used to hold information rather than the execution path, so the heap can be accessed at any time. Compared to stacks, heaps do not have any access restrictions, heaps are like old clothes on a bed, we don’t take the time to sort them out, because we can always find a piece of clothing we need, and stacks are like shoes stacked in a locker Box, we can only start from the top box until we find the right one.

If you need to get the exact size of a type or a variable on a specific platform, you can use the sizeof method. The expression sizeof(type) yields the storage size in bytes to store the object or type.

1. Value types

All value types of C# are implicitly derived from System.ValueType;
determine whether it is a value typeType.IsValueType

——Built-in value types——

Value types include integer, floating point, character, boolean, enumeration, etc.

Value type variables can be directly assigned to a value. From the perspective of memory storage space, the value of the value type is stored in the stack, and each time the value is accessed, it will be operated in this memory.
insert image description here

Integer (including single character char)

Integer is the type that stores integers. According to the range of stored values, C# divides integers into byte type, short type, int type, long type, etc., and defines signed and unsigned numbers respectively.

Signed numbers can represent negative numbers, unsigned numbers can only represent positive numbers

The unsigned types short, int, and long all have the type name prefixed with the u character.

The byte type is special, it stores an unsigned number, and its corresponding signed number is sbyte.

The character type can only store one character, it occupies two bytes and can store one Chinese character.
The character type is represented by the char keyword, and the characters stored in the char type need to be enclosed in single quotation marks, such as 'a', '中' and so on.

floating point

The floating point type refers to the decimal type. The floating point type has float, double, and decimal in the C# language. float is a single-precision floating-point type, double is a double-precision floating-point type,

In addition to integers, values ​​that also contain fractional parts are "floating point types" (floating point data types).

High precision type

decimal is a high-precision floating-point type.

If the numerical value to be processed requires high precision, decimal (high-precision floating-point number) can be used, which is more accurate than float (floating-point number) and double (double-precision floating-point number).

boolean

The boolean type is declared with bool, which has only two values, true and false.

When a value has only two states, it can be declared as a boolean type, for example, whether to agree to the agreement, whether to buy an item, etc.

Boolean values ​​are also often used in conditional judgment statements, such as judging whether a value is even, judging whether a date is a working day, etc.

-- User Defined Value Type --

In addition to the basic types predefined by C#, there are two custom value types, namely structs and enumerations.

Structure type (derived from System.ValueType)

 public struct book
{
    
    
   public string bookname;
   public string bookno;
   public int bookwrite;
}

Using the structure is also very simple, the code is as follows:

  Book book;
  book.bookname = "C#入门"
  book.bookno   = "www.Microsoft.com"
  book.bookwrite= "Microsoft"

You can use the new keyword to initialize structures, and structures can also use constructors.

Enumeration type (derived from System.Enum)

Enumeration, enumeration is a user-defined integer type. The significance of enumeration is that it better realizes the readability of code and the reusability of data. Imagine defining the red color in the system and using color.red to compare It is easier to understand or use 255255 to understand. Use the enum keyword to define an enumeration. The example is as follows:

public enum booktype
{
    
    
   language =0,
   internet =1,
   novel    =2
}

It is also very simple to use, the code is as follows:

   booktype booktype  =booktype.language;

2. Reference types

Array (derived from System.Array)
user-defined type:
Class: class (derived from System.Object);
Interface: interface (Interface is not a "thing", so there is no question of where to derive from.
Delegate: delegate (derived from System.Delegate).
object (alias for System.Object);
String: string (alias for System.String).

Reference types do not contain the actual data stored in the variable, but they contain a reference to the variable.

When a reference type is created, a reference variable is first created in the stack, then the object itself is created in the heap, and then the first address of the memory where the object is located is assigned to the reference variable.

In other words, a reference variable holds a memory location. When using multiple variables, reference types can point to the same memory location. If the data in a memory location is changed by one variable, other variables will automatically reflect this change in value.

Array (derived from System.Array)

User-Definable Reference Types

class class delegate delegate, interface interface

Object type

The Object type is the ultimate base class for all data types in the C# Common Type System (CTS). Object is an alias for the System.Object class. So an Object type can be assigned a value of any other type (value type, reference type, predefined type or user-defined type). However, before assigning the value, a type conversion is required.

When a value type is converted to an object type, it is called boxing; on the other hand, when an object type is converted to a value type, it is called unboxing.

object obj;
obj = 100; // 这是装箱

String type

The String type allows you to assign any string value to a variable. The String type is an alias for the System.String class. It is derived from the Object type. A value of type String can be assigned in two forms: quotes and @quotes.

3. Pointer types

A reference is usually a pointer. We won't use pointers explicitly, they are managed by the Common Language Runtime (CLR).

A pointer (or reference) is different from a reference type because when we say something is a reference type we mean that we access it through a pointer. A pointer is a memory space, and it points to another memory space. Like stack and heap, pointers also take up memory space, but their value is a memory address or null.

Memory allocation when types are nested

What's more confusing is when reference types contain value types, and when value types contain reference types.
Here are a few guidelines, please be sure to understand with examples!

  1. Reference types are always placed on the heap.

  2. Value types and pointers are always placed where they are declared. (This is a little more complicated and requires knowing how the stack works before you can tell where it was declared.)

  3. When value type data is declared in a method body (function), they are placed on the stack.

  4. Value type data is also sometimes placed on the heap. Remember this rule - value types are always placed where they are declared. If a value type data is declared outside the method body and exists in a reference type, it will be replaced by the reference type on the heap.

——Example——

Link to the original example

array instance

Consider an array:

int[] reference = new int[100];

By definition, arrays are reference types, so of course int arrays are reference types (ie reference.GetType().IsValueType is false).

The elements of the int array are all ints. By definition, int is a value type (ie reference[i].GetType().IsValueType is true). So is the value type element in the reference type array on the stack or the heap?

If you use WinDbg to look at the specific location of reference[i] in memory, you will find that they are not on the stack, but on the managed heap.

Actually, for arrays:

TestType[] testTypes = new TestType[100];

If TestType is a value type, storage space is allocated for 100 elements of value type on the managed heap at a time, and these 100 elements are automatically initialized and stored in this memory.

If TestType is a reference type, space will be allocated for testTypes in the managed heap first, and no elements will be automatically initialized at this time (that is, testTypes[i] are all null). When there is code to initialize an element in the future, the storage space of this reference type element will be allocated on the managed heap.

class instance

//类
public class  ReferenceTypeClass
{
    
    
    private int  _valueTypeField;
    public  ReferenceTypeClass()
     {
    
    
         _valueTypeField = 0 ;
     }
    public void  Method()
     {
    
    
        int valueTypeLocalVariable = 0 ;
     }
}
ReferenceTypeClass referenceTypeClassInstance = new ReferenceTypeClass();
//Where is _valueTypeField?

referenceTypeClassInstance.Method();
//Where is valueTypeLocalVariable?

//结构体
public struct  ValueTypeStruct
{
    
    
    private object  _referenceTypeField;
    public void  Method()
     {
    
    
         _referenceTypeField = new object ();
        object referenceTypeLocalVariable = new object ();
     }
}
ValueTypeStruct valueTypeStructInstance = new  ValueTypeStruct();
valueTypeStructInstance.Method();
//Where is _referenceTypeField?And where is referenceTypeLocalVariable?

Just looking at valueTypeStructInstance, this is a structure instance, which seems to be thrown onto the stack in one piece. But the field _referenceTypeField is a reference type, and the local variable referenceTypeLocalVariable is also a reference type.

I have the same problem with referenceTypeClassInstance, referenceTypeClassInstance itself is a reference type and it seems that it should be deployed on the managed heap as a whole. But the field _valueTypeField is a value type, and the local variable valueTypeLocalVariable is also a value type. Are they on the stack or on the managed heap?

The rule is:

A reference type is deployed on the managed heap;
a value type is always allocated where it is declared: as a field, it is stored with the variable (instance) to which it belongs; as a local variable, it is stored on the stack.
Let's analyze the above code. For reference type instances, i.e. referenceTypeClassInstance:

From the context, referenceTypeClassInstance is a local variable, so it is deployed on the managed heap and held by a reference on the stack; the
value type field _valueTypeField is part of the reference type instance referenceTypeClassInstance, so it is deployed in the managed instance along with the reference type instance referenceTypeClassInstance On the heap (somewhat similar to the case of arrays);
valueTypeLocalVariable is a value type local variable, so it is deployed on the stack.
And for value type instances, namely valueTypeStruct:

According to the context, the value type instance valueTypeStructInstance itself is a local variable rather than a field, so it is located on the stack;
its reference type field _referenceTypeField does not have the problem of following, it must be deployed on the managed heap and held by a reference (the reference is part of valueTypeStruct, on the stack);
its reference type local variable referenceTypeLocalVariable is apparently deployed on the managed heap and held by a reference on the stack.
So, simply saying "value types are stored on the stack, reference types are stored on the managed heap" is not correct. It must be analyzed on a case-by-case basis.

Guess you like

Origin blog.csdn.net/weixin_44394801/article/details/119791004