当前位置:编程学习 > 网站相关 >>

由浅入深CIL系列:3.通过CIL观察.NET值类型和引用类型的内存分配

  一、在.NET中,内存分配是非常重要的一大块,为了更深入的了解其分配情况,本节中我们将利用一个实例来查看其CIL语言分析内存的分配情况。下面我们首先来看实例C#源码如下:
    class Program   

{      

  static void Main(string[] args)       

{          

  //将a+b+c,打印结果           

 int a = 3;          

  int b = 19;           

double c = 443.25;           

Console.WriteLine(a + b + c);           

 //分别打印d,e,d+e            string d = "Hello World!";           

 string e = "Print Word!";           

 Console.WriteLine(e);          

  Console.WriteLine(d);          

  Console.WriteLine(d + e);       

}   

 }      

  二、接下来我们看这段程序的CIL代码,通过这段代码我们大概能够猜出分别代表了什么意思。
.method private hidebysig static void  Main(string[] args) cil managed

{

//第一段声明  .entrypoint  // 代码大小       71 (0x47)  .maxstack  2  .locals init ([0] int32 a,           [1] int32 b,           [2] float64 c,           [3] string d,           [4] string e)//第二段值类型内存存储情况  IL_0000:  nop  IL_0001:  ldc.i4.3  IL_0002:  stloc.0  IL_0003:  ldc.i4.s   19  IL_0005:  stloc.1  IL_0006:  ldc.r8     443.25  IL_000f:  stloc.2  IL_0010:  ldloc.0  IL_0011:  ldloc.1  IL_0012:  add  IL_0013:  conv.r8  IL_0014:  ldloc.2  IL_0015:  add  IL_0016:  call       void [mscorlib]System.Console::WriteLine(float64)//第三段引用类型内存存储情况  IL_001b:  nop  IL_001c:  ldstr      "Hello World!"  IL_0021:  stloc.3  IL_0022:  ldstr      "Print Word!"  IL_0027:  stloc.s    e  IL_0029:  ldloc.s    e  IL_002b:  call       void [mscorlib]System.Console::WriteLine(string)  IL_0030:  nop  IL_0031:  ldloc.3  IL_0032:  call       void [mscorlib]System.Console::WriteLine(string)  IL_0037:  nop  IL_0038:  ldloc.3  IL_0039:  ldloc.s    e  IL_003b:  call       string [mscorlib]System.String::Concat(string,                                                              string)  IL_0040:  call       void [mscorlib]System.Console::WriteLine(string)  IL_0045:  nop  IL_0046:  ret} // end of method Program::Main        首先我们看第一段CIL代码所示,声明了程序的进入点,以及定义了5个局部的变量其索引值分别为0,1,2,3,4,变量名为a,b,c,d,e。

  .entrypoint                       //定义了程序的进入点  // 代码大小       71 (0x47) //表明代码总共大小71个字节  .maxstack  2                      .locals init ([0] int32 a,      //在索引的0,1,2,3,4处定义了5个局部变量            [1] int32 b,           [2] float64 c,           [3] string d,           [4] string e)         其次我们来看第二段CIL代码,这是值类型的直接存储在栈中的数据,直接取出相加即可。

//第二段值类型内存存储情况      IL_0000:  nop //int a = 3;    //将整数值 3 作为 int32 推送到计算堆栈上      IL_0001:  ldc.i4.3                //将堆栈顶部的3弹出并且存储到索引为1处得局部变量b      IL_0002:  stloc.0    //int b = 19;             //将整数19作为int32推送到计算机堆栈上      IL_0003:  ldc.i4.s   19           //将堆栈顶部的19弹出并且存储到索引为1处得局部变量b      IL_0005:  stloc.1   //double c = 443.25;              //将所提供的 float64 类型的值443.25作为 F (float) 类型推送到计算堆栈上    //从这里可以看出C# Double类型==MSIL里面的float64类型      IL_0006:  ldc.r8     443.25       //将堆栈顶部的443.25弹出并且存储到索引为2处得局部变量b      IL_000f:  stloc.2//a+b    //将索引 0 处的局部变量a值3加载到计算堆栈上    IL_0010:  ldloc.0    //将索引 1 处的局部变量b值19加载到计算堆栈上    IL_0011:  ldloc.1    //将两个值相加并将结果推送到计算堆栈上,结果为22    IL_0012:  add//a+b得到的值22+c    //将位于计算堆栈顶部的值22转换为 float64    IL_0013:  conv.r8    //将索引 2 处的局部变量b值443.25加载到计算堆栈上    IL_0014:  ldloc.2    //将两个值相加并将结果465.25推送到计算堆栈上    IL_0015:  add    //调用mscorlib程序集内的函数打印值465.25    IL_0016:  call       void [mscorlib]System.Console::WriteLine(float64)启发:

1.在.NET的CIL语言中首先建立一个变量的索引集合。然后在每次初始化值类型的时候先将值类型的值推到计算堆栈上,然后马上将堆栈上顶部的对应值存到对应的索引项中。

2.值类型并没有入堆,而是直接在栈上使用。

3.C#中的Double类型在CIL中实质上就是float64类型,且int32类型和float64类型一起做运算的时候,需要先将int32类型转为float64类型。

        再次我们看以下代码,以观察引用类型在内存中的存储方式和使用方法。

//第三段引用类型内存存储情况    IL_001b:  nop    //为Hello World!字符串分配内存,并且推送其对象引用到计算堆栈上。    IL_001c:  ldstr  

补充:综合编程 , 其他综合 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,