读懂IL代码(二)
上一篇提到了最基本的IL代码,应该是比较通俗易懂的,所以有了上一篇的基础之后,这篇便要深入一点点的来讲述了。
首先我必须再来说一些重要的概念:
Evaluation Stack(评估栈):这是由.NET CLR在执行时候自动管理的记忆体,每一个线程都有自己的评估栈,也就是说,它是用来存储临时变量的线程栈(应该可以这么理解)。值类型存储数据,引用类型存储地址。
Call Stack(调用栈):这也是由.NET CLR在执行时候自动管理的记忆体,每一个线程都有自己的调用栈,每一次调用method,就会产生一个栈帧(stack frame),当方法结束的时候,此栈帧就会被丢弃。
大家一定疑问怎么都是栈呀,堆到哪里去了嘞,大家别急,下面说:
Managed Heap:这是动态配置的记忆体,由Garbage Collector(GC)执行时自动管理,整个程序共用一个。我把这个理解为托管堆,用来存储引用类型的值。
这一篇主要是以引用类型为主来讲述IL代码。
大家都知道把值类型变成引用类型是采用装箱的操作,所以这里也先说一下装箱的过程:
(1)内存分配,在Managed Heap(托管堆)中分配一个内存空间;
(2)将值类型的字段拷贝到分配的内存中;
(3)将托管堆中的对象地址返回给新的对象,Over。

以上是一些基本知识点,现在主要来讲解IL代码:
正规代码如下:

我用Reflector进行查看IL代码:

上图就是IL代码了,经过上一篇的介绍,我觉得这里大家应该也看得懂吧,下面我就来解释这段IL代码吧。
.method private hidebysig static void Main(string[] args)cilmanaged
{
.entrypoint //入口
.maxstack 2 //评估栈可容纳数据项的最大个数。
.locals init (
[] string str,
[] int32 num) //定义并初始化参数,并存入局部变量表(Call Stack)中。
L_0000: nop //No Operation
L_0001: ldstr "Helius" //将字符串“Helius”压入评估栈中。
L_0006: stloc.0 //将字符串从评估栈中弹出,赋值给局部变量表的第0个变量。
L_0007: ldc.i4.s 0x1b //解析:int类型的数值大小不一样,IL代码也是不一样的。比如int i=-1;IL代码为ldc.i4.M1;当i的值大于等于9的时候,IL代码就为ldc.i4.s(i的十六进制表示形式),当i的值小于等于-2时,IL代码表示为ldc.i4.s(i)。
L_0009: stloc.1 //将值从评估栈中弹出,赋值给局部变量表的第1个变量。
L_000a: ldloca.s num //取出局部变量表中num的值“27”并压入评估栈中。
L_000c: call instance string [mscorlib]System.Int32::ToString() //从评估栈中取出数值“27”,调用ToString方法转成string类型并将引用存入评估栈中。
L_0011: ldloc.0 //取出局部变量表中的第0个位置元素值“Helius”,并压入评估栈,(此时评估栈中有两个值,字符串“Helius”和“27”的引用地址)。
L_0012: call string [mscorlib]System.String::Concat(string, string) //调用String类的Concat方法把字符串拼接并存入托管堆中,把引用地址返回给评估栈。
L_0017: call void [mscorlib]System.Console::WriteLine(string) //调用输出方法,调用输出方法后评估栈中的值(指向托管堆中字符的地址)会被回收。
L_001c: nop
------------------------------------------分割线---------------------------------------------------------------------------------------------------
L_001d: ldloc.1 //取局部变量表中的第1个位置参数num值,存入评估栈中。
L_001e: box int32 //把num值27装箱,并返回托管堆中的地址存入评估栈中。
L_0023: ldloc.0 //去局部变量表中的第0个参数,并压入评估栈中。
L_0024: call string [mscorlib]System.String::Concat(object, object)//弹出评估栈中两个值,并调用String的Concat方法把字符拼接,存入托管堆中,并返回引用地址到评估栈中。
L_0029: call void [mscorlib]System.Console::WriteLine(string) //调用输出方法。
L_002e: nop
L_002f: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()//调用ReadKey方法
L_0034: pop //把评估栈的内容清空
L_0035: ret //return 标记返回
} 以图来解释上面的例子可能更明白一点(程序员学会画图很重要,我记得去面试的时候,面试官还叫我画项目的架构图):
图1图2
图3
从以上的图中可以明显看出调用方法与装箱的流程。引用类型都是存放在托管堆里面的,而栈只存放引用类型的地址,这点是要特别注意的。
下一篇我会写方法,委托和类的IL代码解析。
读懂IL代码(二)的更多相关文章
- 读懂IL代码就这么简单(二)
一 前言 IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致.个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 ...
- 【转载】读懂IL代码就这么简单(二)
一 前言 IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致.个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 ...
- 读懂IL代码就这么简单(三)完结篇
一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍 这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认 ...
- 读懂IL代码就这么简单 (一)
一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉 ...
- 读懂IL代码就这么简单
原文地址:http://www.cnblogs.com/zery/p/3366175.html 一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不 ...
- 读懂IL代码就这么简单 ---- IL系列文章
读懂IL代码就这么简单 (一) 读懂IL代码就这么简单(二) 读懂IL代码就这么简单(三)完结篇 出处:http://www.cnblogs.com/zery/tag/IL%20%E7%B3%BB%E ...
- 【转载】读懂IL代码就这么简单(三)完结篇
一 前言 写了两篇关于IL指令相关的文章,分别把值类型与引用类型在 堆与栈上的操作区别详细的写了一遍这第三篇也是最后一篇,之所以到第三篇就结束了,是因为以我现在的层次,能理解到的都写完了,而且个人认为 ...
- 【转载】读懂IL代码就这么简单 (一)
一前言 感谢 @冰麟轻武 指出文章的错误之处,现已更正 对于IL代码没了解之前总感觉很神奇,初一看完全不知所云,只听高手们说,了解IL代码你能更加清楚的知道你的代码是如何运行相互调用的,此言一出不明觉 ...
- 读懂IL代码(一)
以前刚开始学C#的时候,总有高手跟我说,去了解一下IL代码吧,看懂了你能更加清楚的知道你写出来的代码是如何运行互相调用的,可是那时候没去看,后来补的,其实感觉也不晚.刚开始看IL代码的时候,感觉非常吃 ...
随机推荐
- PL/SQL 异常处理
SQL> set serveroutput on SQL> declare name varchar2(10); begin select ename into name from ...
- 通过dblink impdp导入
实验: 源数据库:10.5.129.160 dwhtest 需要导入的数据库:10.5.129.130 dwhtest 在10.5.129.130上创建DBLINK SQL> create p ...
- poj3709
首先我们发现将一段数变为同一个数比间隔着搞肯定优,因为数列是升序的,然后不难得到方程式f[i]=min(f[j]+sum[i]-sum[j]-(i-j)*a[j+1]) (i-j>=m)简单的斜 ...
- bzoj3124
很好的一道treedp,当然也挺烦的首先不难想到先求出一个直径,然后穷举每条边,看他删除之后直径大小是否会变,变了的话就是必须经过的边下面我们就要想怎么优化,本人语言表达略差,还是配合程序说吧. ty ...
- nodejs之日志管理
开发一个项目时,可以通过控制台输出或者debug来获取到项目的运行信息.当项目上线时,我们就需要通过日志来分析.如同Java的log4j,nodejs中也有相关的log4js.使用过log4j的同学应 ...
- 【转】linux 中dd命令使用详解
原文网址:http://xiaozhuang.blog.51cto.com/4396589/850657 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究 ...
- Hibernate(二)Hibernate 实例
上篇Hibernate(一)JDBC简介,我们主要对JDBC进行了简单介绍和使用说明,这次我们做一个Hibernate简单实例,通过这个实例对比Hibernate和JDBC,了解Hibernate的优 ...
- js 传参数
引用js实现传参数,然后在js文件里面动态加载东西,比如传递参数然后动态加载皮肤颜色,而我为了实现多语言,一般人家传递参数是为了区分版本用的还有清除js缓存问. <script src=&quo ...
- UVa12063 Zeros and Ones
神坑 1竟然还要取模 在后面填数多好的 #include<cstdio> #include<cstring> #include<cstdlib> #include& ...
- 如何制作iso文件
UltraISO 9.6.2.3059中文完美破解安装版 http://www.upantool.com/qidong/2011/UltraISO_v9.5.0.2800.html 软碟通v9.6.2 ...
图2
图3