看个简单的例子,只用于演示,不考虑合理性:
1 using System; 2 3 namespace Test 4 { 5 class Program 6 { 7 static void Main(string[] args) 8 { 9 int height = 170; 10 int weight = 60; 11 People.Find(); 12 People developer = new Developer()(height, weight); 13 bool isHealthyWeight = developer.IsHealthyWeight(); 14 bool isRich = developer.IsRich(); 15 } 16 } 17 18 class People 19 { 20 int _height; 21 int _weight; 22 23 public People(int height, int weight) 24 { 25 _height = height; 26 _weight = weight; 27 } 28 29 public virtual bool IsRich(); 30 31 public bool IsHealthyWeight() 32 { 33 var healthyWeight = (Height - 80) * 0.7; 34 return Weight <= healthyWeight * 1.1 && Weight >= healthyWeight * 0.9; 35 } 36 37 public static string Find(string id) { return ""; } 38 } 39 40 class Developer : People 41 { 42 public Developer(int height, int weight) : base(height, weight) 43 { } 44 45 public override bool IsRich() 46 { 47 return false; 48 } 49 } 50 51 } |
*图片不清楚可以放大看
首先判断类型是否都加载,用到了int,bool,string,这些是在mscorlib.dll程序集的system命名空间下,所以先加载mscorlib.dll程序集,再把int,bool,string加到类型对象里。另外还有我们自己定义的Developer和People,也把类型对象创建好,另外也别忘了基类object,也要加载进来。(实际上还有double啊,这里就没画了)另外继承类的类型对象里面都有个字段指向基类,所以才能往上执行到基类方法表里的方法。
局部变量都在线程栈上,Find()方法是静态方法,直接去People类型对象的方法表里去找,找到后看是否有存根标识,没有的话做JIT编译,有的话直接运行。
developer的实例化虽然是用People定义的,但实例还是Developer,所以developer的类型对象指针指向Developer,对象里除了类型对象指针还有实例字段,包括基类的。内存分配在托管堆上,并把地址给到线程栈上的变量中。
虚函数也一样,在运行时已经确定是Developer,所以会调用Developer方法表里的IsRich方法,一样先JIT,再运行。
以上就是一个简单的C#程序的运行过程和在内存上的表现,本篇主要内容来自CLR via C#这本书,小弟算是总结一下,谢谢观看。
相关文章: