【.Net底层剖析】stfld指令-给对象的字段赋值

.Net底层剖析目录章节

引言:

  这篇我们讲解在.net  IL中间语言中,经常见到的指令stfld。

  该指令经常用在给一个对象的字段赋值。

一、指令用途:

  MSDN解释如下:

  Replaces the value stored in the field of an object reference or pointer with a new value.

  翻译过来就是:用一个新值替换对象字段的值

二、命名空间和程序集

  命名空间是在  System.Reflection.Emit这个里面

  程序集是mscorlib(mscorlib.dll中)

三、指令执行机制

  工作原理即堆栈转换行为如下:

  按照先后顺序:

    1.将一个对象引用或指针压入堆栈

    2.将值被压入堆栈

    3.该值和对象的引用/指针从堆栈中弹出,对象的字段更新为替换的值

四、 实例代码分析:

C#程序:

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Test test1=new Test();//new一个Test对象
            test1.i = 12;//将Test对象的字段i赋值为12
        }

        /// <summary>
        /// 测试类
        /// </summary>
        public class Test
        {
            public int i = 100;
        }
    }
}

IL 程序Main方法

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       16 (0x10)
  .maxstack  2
  .locals init ([0] class ConsoleApplication1.Program/Test test1)
  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication1.Program/Test::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.s   12
  IL_000a:  stfld      int32 ConsoleApplication1.Program/Test::i
  IL_000f:  ret
} // end of method Program::Main

我们来逐行分析下main方法的IL代码

.entrypoint  //定义函数的入口点

// Code size       16 (0x10)//代码大小为16

.maxstack  2//栈的大小为2

.locals init ([0] class ConsoleApplication1.Program/Test test1)//定义一个变量为test1,存储在<本地变量列表>中第一个变量中

IL_0000:  nop//空操作

IL_0001:  newobj     instance void ConsoleApplication1.Program/Test::.ctor()//new 一个Test对象,一个引用指向这个对象,引用存放在栈上,

对象存放在堆上面

IL_0006:  stloc.0//将引用弹栈,存放到<本地变量列表>中的第一个变量中

IL_0007:  ldloc.0//将<本地变量列表>中第一个变量的值压入堆栈

IL_0008:  ldc.i4.s   12//将int 12压入堆栈

IL_000a:  stfld      int32 ConsoleApplication1.Program/Test::i//将堆栈的栈顶的值赋值给堆栈的第二个值,即test.i=12

IL_000f:  ret//函数返回

五、内存分析

在指令stfld 执行之前的内存图

堆栈中存放12,test1的地址,<本地变量列表>第一个变量中存放的是test1的地址,堆中存放的是test1指向的一个对象,其中test1.i=100

在指令stfld 执行之后的内存图

堆栈中的12,test1的地址弹出,<本地变量列表>第一个变量中存放的是test1的地址不变,堆中存放的是test1.i=12

六、总结

本篇主要讲的就是对象的字段如何在内存中是如何赋值的,以及从每一行IL指令分析stfld 的执行过程。从底层分析对象的字段的赋值,可以更加清晰地看到赋值的过程。

下篇我会从.net底层剖析参数的传递,有兴趣的可以关注我哦!

时间: 2024-11-23 22:08:10

【.Net底层剖析】stfld指令-给对象的字段赋值的相关文章

.Net底层剖析目录章节

[.Net底层剖析]目录章节 1.[深入浅出.Net IL]1.一个For循环引发的IL 2.[.Net底层剖析]stfld指令-给对象的字段赋值 3.[.Net底层剖析]参数传递 4.[.Net底层剖析]装箱与拆箱

Redis源码剖析(八)--对象系统

对象的类型与编码 在 Redis 中新创建一个键值对时, 我们至少会创建两个对象, 一个对象用作键值对的键(键对象), 另一个对象用作键值对的值(值对象).Redis 中的每个对象都由一个 redisObject 结构表示: typedef struct redisObject { // 类型 unsigned type:4; // 编码 unsigned encoding:4; // 对象最后一次被访问的时间 unsigned lru:REDIS_LRU_BITS; /* lru time (

python源码剖析笔记1——Python对象初见

python源码剖析笔记1--Python对象初见 工作整两年了,用python最多,然而对于python内部机制不一定都清楚,每天沉醉于增删改查的简单逻辑编写,实在耗神.很多东西不用就忘记了,比如C语言,正好,python源码用C写的,分析python源码的同时又能温故C语言基础,实在是件很好的事情.另外,还有陈儒大神的<python源码剖析>做指引,分析也不至于没头没脑.期望在一个月的业余时间,能有所小成,以此为记. 1 python中的对象 python中,一切东西都是对象,在c语言实现

《python源码剖析》笔记 python对象初探

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.      在python中,对象就是为C中的结构体在堆上申请的一块内存.对象不能被静态初始化,也不能在栈空间生存.但内建的类型对象都是被静态初始化的. 2.      对象创建后大小不变.可变对象有一指针指向可变大小的内存区域. 3.      对象机制的基石:PyObject 定长对象: typedef struct _object{ PyObject_HEAD }PyObject

Python源码剖析笔记2-Python整数对象

Python源码剖析笔记2-Python整数对象 本文简书地址: http://www.jianshu.com/p/0136ed90cd46 千里之行始于足下,从简单的类别开始分析,由浅入深也不至于自己丧失信心.先来看看Python整数对象,也就是python中的PyIntObject对象,对应的类型对象是PyInt_Type. 1 Python整数对象概览 为了性能考虑,python中对小整数有专门的缓存池,这样就不需要每次使用小整数对象时去用malloc分配内存以及free释放内存.pyth

指令定义对象--进阶阶段

指令定义对象 每个指令定义的工厂函数,需要返回一个指令定义对象,编译器/$compile 在编译时就根据这个定义对象对指令进行展开. 指令定义对象的常用属性如下: link link函数负责实现DOM和scope的数据绑定,通常在link里执行DOM事件监听和数据变化监听. link函数在template执行后被调用.link是最常用的属性,一个指令的逻辑通常在link函数 里实现. link函数的形式如下: function link(scope,iElement,iAttrs,control

C++:基类与派生类对象之间的赋值兼容关系

4.5 基类与派生类对象之间的赋值兼容关系 在一定条件下,不同类型的数据之间可以进行类型转换,例如可以将整型数据赋给双精度型变量. 在赋值之前,先把整型数据转换为双精度型数据,然后再把它双精度型变量.这种不同类型之间的自动转换,称为赋值兼容.在基类和派生类对象之间也存在有赋值兼容关系,基类和派生类对象之间的赋值兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来代替.因为,通过公有继承,除了构造函数和析构函数外,派生类保留了基类其他的所有的成员.那么,派生类就具有基类的全部功能,凡

Dream------scala--类的属性和对象私有字段实战详解

Scala类的属性和对象私有字段实战详解 一.类的属性 scala类的属性跟java有比较大的不同,需要注意的是对象的私有(private)字段 1.私有字段:字段必须初始化(当然即使不是私有字段也要赋值) 2.属性默认是public级别的,而且无法用public修饰. 3.可以有很多类,并且默认是public级别(如果声明的时候加上会报错,不知为何) 4.如果属性是public的,会默认生成类属性的getter和setter方法,无需显示的提供getter,setter方法 5.私有字段(用p

[转]Hibernate查询对象所有字段,单个字段 ,几个字段取值的问题

原文地址:http://www.ablanxue.com/prone_3552_1.html 1. 查询整个映射对象所有字段 Java代码 //直接from查询出来的是一个映射对象,即:查询整个映射对象所有字段 String hql = "from Users"; Query query = session.createQuery(hql); List<Users> users = query.list(); for(Users user : users){ System.