通过简单的代码分析.NET对象内存分配

System.Windows.Forms.Button btn = new Button();

以中间赋值符号为界限,先看左边。System.Windows.Forms 是命名空间,放在一边。后面是 Button btn,也就是类型名称,变量名的形式。

其实这跟 int i 没区别,因为 int i 就是类型名称,变量名的形式。 i 变量在栈上分配地址空间,因此 btn 变量也是在栈上分配地址空间。

再看赋值符号右边,new Button(); new 运算符在绝大多数的语言中都是用来在堆上分配内存的。堆内存有地址空间大,申请和释放需要调用者维护的特点。 new 运算符在堆上分配了一块用于存放 Button 类型对象的连续地址空间。

同时,new 运算符还会返回指向 Button 对象的首地址。后边的 () 表示在对象创建之后,调用该类型的默认构造函数。 btn = new Button() 的意思就是把在堆上分配的Button 类型对象的首地址保存在堆的 btn 变量中。

当调用 btn.Text = 类似这样的属性时,先在堆栈上找到btn 变量所在地址,然后从该地址中取出堆上Button 对象的首地址,然后再去托管堆上找 Button 对象,并修改 Text 属性。其实 Text 属性是个String 类型也就是引用类型对象,其实是在堆的另外的地方分配了一块空间的。

当执行 btn = null 时,表示对上的 Button 对象此时是 unreachable 的情况,因为没有谁再保存着 Button 类型的对象的首地址,因此也就无法再使用这个Button 对象了。

此时如果GC 启动,会将这个对象标记,但并未进行回收。

一旦决定回收这个 Button 对象了,首先会把这个 Button 对象的首地址插入到 FinalizeQueue 队列中,然后等待 GC 的 Finalize 线程调用 Button 对象的析构函数。

当 GC 再次启动时,如果 Button 对象的析构函数已经调用完成了,那么 GC 就将 Button占用的地址空间回收,并且对内存对象进行迁移和整理。

这主要是为了保持内存中可用地址空间是连续的。

做这个操作的时候,由于会挪动托管堆上的很多对象,因此会导致其他对象比如 Label.Text 类似这样的寻址失效。

因此 GC 要把当前应用程序执行代码的线程挂起,停止执行。当内存对象迁移完成之后,再恢复运行。

这就是为什么每次GC启动特消耗资源的原因,一方面要利用算法迁移内存中的对象,使大片可用地址空间保持连续,另一方面要挂起应用程序执行线程,导致应用程序短时间停止响应让应用程序运行变慢(毫秒或者几十毫秒级别)。

IDispose 接口设计

IDispose 接口这种设计模式是为了让一些资源的释放变成程序员可控。上面说到的 GC 自动回收对象,需要GC两次启动才能完成一个对象的回收操作。

IDispose 接口中含有一个 Dispose 方法,在该方法中写入释放资源的函数,并调用 System.GC.SuppressFinalize(this); 方法,告诉 GC 这个对象不必再放入FinalizeQueue 队列中等待调用析构函数了。

这样可以让GC 一次完成对象的回收。

以上是针对一般对象,对于块头特别巨大的对象比如大于85KB 的对象,有专门的大对象堆LOH进行存放。

但是LOH 上的对象一旦释放,就不会再做内存整理了,因为在内存中拷贝这么大的对象效率太低。

GC 工作模式

GC 有两种工作模式,服务器和工作站。

  • 工作站模式下,所有的CPU和内存都会看做成是一体的;
  • 服务器模式下,一个 CPU 一组堆。

目前 .NET 服务器模式下最多支持32个GC 一起工作。因此,对于特别特别特别牛逼的机器,比如64核的服务器,其实 .NET 是用不上的。只能是32个核,其他都是摆设。

服务器模式是为了提高并行度,减少 GC 给应用程序带来的影响。以至于后来又有了concurrent GC 模式,其实都是为了尽量减少应用程序挂起的时间提高程序运行效率。

但是不管是哪种模式,GC 只要工作就会挂起工作线程。因此,代码中恰当的对象分配才是提高程序效率的根本。

内容整理自广州 .NET 微软技术俱乐部微信群内发言人:李争

微软(中国)有限公司全渠道事业部资深技术顾问。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

如有任何疑问,请与我联系 ([email protected]) 。

猜你喜欢

转载自www.cnblogs.com/MingsonZheng/p/10206595.html