惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
酷 壳 – CoolShell
酷 壳 – CoolShell
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
腾讯CDC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Jina AI
Jina AI
N
Netflix TechBlog - Medium
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
GbyAI
GbyAI
B
Blog
F
Fortinet All Blogs
T
Tailwind CSS Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
G
Google Developers Blog
A
About on SuperTechFans
C
Check Point Blog
Microsoft Security Blog
Microsoft Security Blog
MyScale Blog
MyScale Blog
B
Blog RSS Feed

博客园 - 刘荣华

VS2005 疑难杂症小解(转) - 刘荣华 - 博客园 面向对象--接口与抽象类的恩恩怨怨 揭开CLR神秘面纱—第一步PE文件 打造自己的Javascript alert confirm对象(一) 一篇非常好的服务器控件原理讲解文章(转载) 利用VS2005的FileUpload控件做一个图片上传类 基础中的基础,关于网页DOCTYPE(文档类型)的定义 SmtpClient学习笔记 测试中常见问题分析及对策 初识MemberShip类 周末(友情篇) 新的环境、新的起点、新的目标 由。NET分层架构所引发的思考(一) 再谈配置文件 shtm答疑 JS代码大全(二) JS代码大全(一) 关于用JS读取XML文档的问题 C#编程规范下载
揭开CLR神秘面纱-----第二步 垃圾回收之(制造垃圾)
刘荣华 · 2007-07-17 · via 博客园 - 刘荣华
 

阅读本章前,要求读者对值类型与引用类型有相当的了解

关于值类型与引用类型的深入讲解,请参见ANYTAO的[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理  

----.NET应用程序初始化的时候所有的引用类型都会被分配到托管堆上面。而只有托管堆里面的资源才能被垃圾回收机制给管理起来。所以,我们要明白,CLR的垃圾回收机制并不是针对所有数据的。我们该手动释放的时候必须得要手动释放。

   我们从何得知这一结论?如何论证这一点?

   程序是如何在CLR中运行的呢?那我们CLR中垃圾回收机制又是怎么样运行的呢?我们是否需要再进一步去研究呢?我们如果不手动释放值类型,它们会常驻我们宝贵的内存空间吗?我不得不承认,这里牵扯到了很复杂的算法和操作系统及Win32编程的相关知识。这可能需要大篇幅的文字来说明这些问题。

   既然有垃圾回收,肯定就有垃圾制造者在制造垃圾。这些垃圾是如何被制造出来的,就是我们今天试图弄清楚的问题。希望能通过以下文字描述清楚,程序运行时各阶段的内存使用状态。

   请看下面的代码:

很明显,上面定义了一个类,一个枚举,一个结构,这是一段表面看似很普通的代码,但其实骨子里却大有乾坤。我们再次打开ILdasm来看下它的真面目。

     可以看的出,两个类都有.ctor,就是说,两个类都有构造函数。点开会发现原来是继承自Object的构造函数。这也就解释了为什么我们定义类的时候就算不显示声明构造函数,系统也会自动给你声明构造函数。功劳来自于CLR.

    细心的朋友又会发现另外一个问题,那这里这个结构明明没有看见构造函数,那它为什么也能new呢?关于这里,可以参考anytao关于new的文章

我这里谈谈自己的看法。我们点开Main函数。会看到如下内容

     

   可以看到,在init的时候,里面传入了11个参数。分别就是我们代码里使用的11个对象。Init指令起的作用是“init specifies that the variables must be initialized to the default values for their respective types” init 指定的变量必须被各自类型的默认值初始化--原文地址

    继续我们上面的问题,结构没有构造函数为什么也能new呢?分析IL代码,发现new class的时候也就是new 引用类型的时候,IL的指令是newobj,并且还instance了相应的构造函数,new struct的时候,IL的指令却是initobj。这似乎就是问题的根源所在。
  先说说newobj指令吧,执行该指令的时候,他会将我们指定的类型实例化,而且根据需要会将新类型中的成员初始化一次,再把这个对象送到托管堆上。然后再根据参数调用构造函数。构造函数对该类型做的操作就是在托管堆中进行了,最后在线程堆上只是把这个对象的引用压栈。(我们的托管堆上其实存在一个指针。该指针就是我们垃圾回收的最高检察官。关于他,咱们以后再做描述。)

    那我们的initobj做了什么工作呢?MSDN上给出的解释很简单。该指令就是初始化值类型。因为编译后,非primitive type的值类型已经存在于线程堆栈上。但是还没有初始化。所以需要做这一步操作。而所有的primitive type在编译时会初始为0.这也就是为什么char和MyStruct同为值类型而char没有init的原因了。    

    通过上面的描述,我们应该可以清晰的看出.NET CLR中的运行过程,对象的创建是一个递归的过程。恰恰也是咱们通常所说的Builer模式的一个体现。至此,我们的“垃圾”都已经制造完毕,下一步可以讨论生成的垃圾该如何回收了。这一步最重要的理解在于初始化。
                                                        MSIL速查手册下载,感谢无私奉献

版权声明:原创技术文章,如需转载,请声明出处。不得用于任何商业形式活动,否则将追究法律责任。

PS:非常感谢sumtec@beijing,剑在上海^^,两位网友提出的意见。