C#---引用类型,值类型和堆栈
1.值类型(System.ValueType类)和栈(Stack)
System.ValueType--bool、byte、char、decimal、double、enum、float、int、long、sbyte、short、struct、unit、ulong、ushort。
栈是编译期间就分配好的内存空间,代码中就栈的大小有明确的定义。栈是连续的内存域,由系统自动分配和维护。
- 栈保存代码的执行步骤--函数调用返回
A->B->C->D 函数调用压栈 返回是弹栈D->C->B->A
- 存放变量-值类型
值类型不一定被分配到栈上,值类型被声明在一个方法体外并且在一个引用类型中,会在堆上进行分配。(成员变量或属性)
- 存储空间释放(垃圾回收)
栈内存无需我们管理,也不受GC管理。栈顶元素使用完毕,立即释放。
2.引用类型(System.Object)和堆(Heap)
System.Object---class、interface、delegate、object、string
堆是程序运行期间动态分配的内存空间,可以根据程序的运行情况确定要分配的堆内存大小。堆是无序的,由用户来控制和释放,若用户不释放,当内存达到一定的特定值时,通过垃圾回收器(GC)回收。
- 存放对象-引用类型
- 存储空间释放
堆则需要GC(Garbage collection:垃圾收集器)清理
在程序运行的时候,每个线程(Thread)都会维护一个自己的专属线程堆栈。
指针:
当一个方法被调用的时候,主线程开始在所属程序集的元数据中,查找被调用方法,然后通过JIT即时编译并把结果(一般是本地CPU指令)放在栈顶。CPU通过总线从栈顶取指令,驱动程序以执行下去。
3. 栈示例:
public int AddFive(int pValue) { int result; result = pValue + 5; return result; }
方法开始调用时,方法参数在栈上分配
方法内部开始执行时,变量result被分配在栈上
方法执行完毕,而且方法返回后
栈上的区域被清理。
4.堆示例
public class MyInt { public int MyValue; } public MyInt AddFive(int pValue) { MyInt result = new MyInt(); result.MyValue = pValue + 5; return result; }
方法被调用时,参数被分配到栈上
方法开始执行,由于MyInt是引用类型,result是指向引用类型的指针
方法执行完毕,栈上内存被清理,但堆中依然存在
当程序需要更多的堆空间时,GC需要进行垃圾清理工作,暂停所有线程,找出所有不可达到对象,即无被引用的对象,进行清理。并通知栈中的指针重新指向地址排序后的对象。当我们使用引用类型的时候,一般是对指针进行的操作而非引用类型对象本身。但是值类型则操作其本身。
5.Dictionary<string,int> foreach无法修改值类型取值(MoveNext报错)
值类型:
Dictionary<string, int> doc = new Dictionary<string, int>(); doc.Add("sl", 1); doc.Add("xm", 2); doc.Add("xl", 3); foreach (var item in doc) { Console.WriteLine(item.Value); }
IL代码:
.method public hidebysig static void TestValueType() cil managed { // 代码大小 106 (0x6a) .maxstack 3 .locals init ([0] class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> doc, [1] valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,int32> V_1, [2] valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<string,int32> item) IL_0000: nop IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldstr "sl" IL_000d: ldc.i4.1 IL_000e: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1) IL_0013: nop IL_0014: ldloc.0 IL_0015: ldstr "xm" IL_001a: ldc.i4.2 IL_001b: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1) IL_0020: nop IL_0021: ldloc.0 IL_0022: ldstr "xl" IL_0027: ldc.i4.3 IL_0028: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::Add(!0, !1) IL_002d: nop IL_002e: nop IL_002f: ldloc.0 IL_0030: callvirt instance valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<!0,!1> class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::GetEnumerator() IL_0035: stloc.1 .try { IL_0036: br.s IL_004f IL_0038: ldloca.s V_1 IL_003a: call instance valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<!0,!1> valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,int32>::get_Current() IL_003f: stloc.2 IL_0040: nop IL_0041: ldloca.s item IL_0043: call instance !1 valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<string,int32>::get_Value() IL_0048: call void [mscorlib]System.Console::WriteLine(int32) IL_004d: nop IL_004e: nop IL_004f: ldloca.s V_1 IL_0051: call instance bool valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,int32>::MoveNext() IL_0056: brtrue.s IL_0038 IL_0058: leave.s IL_0069 } // end .try finally { IL_005a: ldloca.s V_1 IL_005c: constrained. valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,int32> IL_0062: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_0067: nop IL_0068: endfinally } // end handler IL_0069: ret } // end of method Program::TestValueType
引用类型:
Dictionary<string, Student> doc = new Dictionary<string, Student>(); Student s = new Student(); s.name = "sl"; s.point = 1; doc.Add("NO1",s); Student t = new Student(); t.name = "xm"; s.point = 2; doc.Add("NO2", t); Student st = new Student(); st.name = "xl"; st.point = 3; doc.Add("NO3", st); foreach(var item in doc) { item.Value.name = "same"; }
IL代码:
.method public hidebysig static void TestObject() cil managed { // 代码大小 184 (0xb8) .maxstack 3 .locals init ([0] class [mscorlib]System.Collections.Generic.Dictionary`2<string,class TestDictionaryIL.Program/Student> doc, [1] class TestDictionaryIL.Program/Student s, [2] class TestDictionaryIL.Program/Student t, [3] class TestDictionaryIL.Program/Student st, [4] valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,class TestDictionaryIL.Program/Student> V_4, [5] valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<string,class TestDictionaryIL.Program/Student> item) IL_0000: nop IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,class TestDictionaryIL.Program/Student>::.ctor() IL_0006: stloc.0 IL_0007: newobj instance void TestDictionaryIL.Program/Student::.ctor() IL_000c: stloc.1 IL_000d: ldloc.1 IL_000e: ldstr "sl" IL_0013: stfld string TestDictionaryIL.Program/Student::name IL_0018: ldloc.1 IL_0019: ldc.i4.1 IL_001a: stfld int32 TestDictionaryIL.Program/Student::point IL_001f: ldloc.0 IL_0020: ldstr "NO1" IL_0025: ldloc.1 IL_0026: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,class TestDictionaryIL.Program/Student>::Add(!0, !1) IL_002b: nop IL_002c: newobj instance void TestDictionaryIL.Program/Student::.ctor() IL_0031: stloc.2 IL_0032: ldloc.2 IL_0033: ldstr "xm" IL_0038: stfld string TestDictionaryIL.Program/Student::name IL_003d: ldloc.1 IL_003e: ldc.i4.2 IL_003f: stfld int32 TestDictionaryIL.Program/Student::point IL_0044: ldloc.0 IL_0045: ldstr "NO2" IL_004a: ldloc.2 IL_004b: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,class TestDictionaryIL.Program/Student>::Add(!0, !1) IL_0050: nop IL_0051: newobj instance void TestDictionaryIL.Program/Student::.ctor() IL_0056: stloc.3 IL_0057: ldloc.3 IL_0058: ldstr "xl" IL_005d: stfld string TestDictionaryIL.Program/Student::name IL_0062: ldloc.3 IL_0063: ldc.i4.3 IL_0064: stfld int32 TestDictionaryIL.Program/Student::point IL_0069: ldloc.0 IL_006a: ldstr "NO3" IL_006f: ldloc.3 IL_0070: callvirt instance void class [mscorlib]System.Collections.Generic.Dictionary`2<string,class TestDictionaryIL.Program/Student>::Add(!0, !1) IL_0075: nop IL_0076: nop IL_0077: ldloc.0 IL_0078: callvirt instance valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<!0,!1> class [mscorlib]System.Collections.Generic.Dictionary`2<string,class TestDictionaryIL.Program/Student>::GetEnumerator() IL_007d: stloc.s V_4 .try { IL_007f: br.s IL_009d IL_0081: ldloca.s V_4 IL_0083: call instance valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<!0,!1> valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,class TestDictionaryIL.Program/Student>::get_Current() IL_0088: stloc.s item IL_008a: nop IL_008b: ldloca.s item IL_008d: call instance !1 valuetype [mscorlib]System.Collections.Generic.KeyValuePair`2<string,class TestDictionaryIL.Program/Student>::get_Value() IL_0092: ldstr "same" IL_0097: stfld string TestDictionaryIL.Program/Student::name IL_009c: nop IL_009d: ldloca.s V_4 IL_009f: call instance bool valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,class TestDictionaryIL.Program/Student>::MoveNext() IL_00a4: brtrue.s IL_0081 IL_00a6: leave.s IL_00b7 } // end .try finally { IL_00a8: ldloca.s V_4 IL_00aa: constrained. valuetype [mscorlib]System.Collections.Generic.Dictionary`2/Enumerator<string,class TestDictionaryIL.Program/Student> IL_00b0: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_00b5: nop IL_00b6: endfinally } // end handler IL_00b7: ret } // end of method Program::TestObject