C#下内存管理--垃圾收集

章节安排程序员

  1. 内存管理简介
  2. 垃圾回收机制
  3. 性能问题
  4. C#下非托管资源的处理
  5. 要强调的几点
  6. References

内存管理简介算法

      对于任何一种编程语言,内存管理都是不得不提很重要的一块内容,但惋惜的是目前为止没有任何一种编程语言对内存管理处理的很是完美,每种语言都在兼顾性能 效率,语法语义易用性等方面折中中有所侧重。例如较之于C#,JAVA等语言C++号称不须要垃圾收集,由于C++自己产生的垃圾不多,诚然这是C++的 优点,这也就是为何在内存受限或者效率优先的环境下优先考虑C++,但它的缺点也是明显的--程序员必须本身控制内存管理,很容易产生内存泄漏,这同时 也造就了C++很难掌握。感谢摩尔定律吧,它促使了垃圾收集这个概念的出现,但较之C++直接操纵内存释放,再牛逼的垃圾收集算法也没法抹去那一层性能上 的损失。数据库

      在讨论以前咱们先明确一点:内存中数据按所处位置不一样能够分为栈内存和堆内存,栈的主要做用是追踪函数调用之间的数据传递(栈上所存储 的数据类型一般是int,char,long,指针等内置值类型和struct。注意一点在多线程环境下,每一个线程都有本身的栈。)因此栈的内存管理一般 由操做系统负责。而咱们所说的内存管理,大都讨论的是堆上内存管理(分配在堆上的类型通常是自定义引用类型:类,接口,字符串,对象实例,C#中委托 等)。关于这一点详情请参照Under  the hood of NET Management。编程

       内存内存管理从生命周期上来分能够分为三个阶段:内存分配,内存生命周期内管理,内存的释放。每一阶段都与程序的运行效率关系密切,以C++为例,在新版 的C++标准中Unique_ptr取代auto_ptr,move语义,引入右值引用等措施极大地提升了STL的效率(详细信息参考Refereces 中关于C++的连接)。而兼顾讨论内存管理的全部内容有点不现实,本篇主要关注内存的释放,确切来说是C#的垃圾回收。    性能优化

垃圾回收机制        数据结构

       首先声明一点所谓垃圾回收,回收的是分配在托管堆上的内存,对于托管堆外的内存,它无能为力。多线程

       讨论垃圾回收机制就不得不提内存的分配,在C运行时堆(C-runtime heap)中,堆是不连续的,咱们new一个新的对象时,系统会检查内存,找一块足够大的内存而后初始化对象,对象被销毁后,这块空间会用于初始化新的对 象。这样作有什么弊端?随着程序运行一直有对象生成释放,内存会变得碎片化,这样有新的大的对象要生成时就必须扩展堆的长度,碎片内存没法获得充分利用, 还有一个弊端是每次建立一个对象时都要检查堆内存,效率不高。而C#托管堆采起连续内存存储,新建立对象时只要考虑剩下的堆内存是否足够大就成,但一直生 成对象而不析构会使托管堆无限增大,怎么维护这样一块连续内存呢?这也就引出了垃圾回收机制。托管堆的大小是特定的,垃圾收集器GC负责当内存不够的时候 释放掉垃圾对象,copy仍在使用的对象成一块连续内存。而这就带来了性能问题,当对象很大的时候,频繁的copy移动对象会下降性能,因此C#的垃圾收 集引入了世代和大对象堆小对象堆的概念。   编程语言

      所谓大对象堆小对象堆从字面意义就能看出其做用,大对象堆主要负责分配大的对象,小对象堆分配小的。但对象大小怎么肯定呢?在.NET Framework中规定,若是对象大于或等于 85,000 字节,将被视为大型对象。当对象分配请求传入后,若是符合该大小阈值,便会将此对象分配给大型对象堆。这个85000字节是根据性能优化的结果肯定。值得 注意的是垃圾回收对大对象堆和小对象堆都起做用。那么分大对象和小对象堆做用是什么呢?仍是性能,对于大对象和小对象区别对待采起不一样灵活的垃圾回收策略 一定比一棍子打死死板的采用同一种策略要好。下面咱们讨论一下在SOH和LOH不一样的垃圾收集策略:   函数

      先说一下世代,之因此分世代,是由于在第0代就能清除大部分对象。请注意,世代是个逻辑上的概念,物理上并无世代这个数据结构。以小对象堆垃圾回收为 例:当一个对象被建立的时候,它被定义为第0代对象,而经历一次垃圾收集后还存余的对象就被纳入了第1代对象,同理通过两次或者两次以上仍然存在的对象就 能够当作第2代对象。虽然世代只是逻辑概念,但它倒是有大小的,对于SOH对象来讲,因为每次垃圾回收都会压缩移动对象,因此世代数越大越在堆底。经历一 次垃圾回收,对象都会被移入下一个世代的内存空间中(下图以小对象堆上垃圾回收为例。对象W至少通过两次垃圾回收而不死,因此放入世代2,X经历了一次垃 圾回收)。而每次一个世代内存达到其阙值,都会引起垃圾收集器回收一次。这么作的好处就是每次垃圾回收器只是回收一个世代的内存,从总体上来看,减小了对 象复制移动的次数。  工具

       

         以上讨论都是针对于SOH,对于SOH对象来讲复制移动较之LOH成本性能要小一点,那么对于LOH呢?复制一个LOH的对象而且清除原来内存位置的字 节,成本至关大,怎么确保它的垃圾回收呢?首先从物理上来讲,LOH在托管堆的堆底,SOH在其上,逻辑上讲LOH对象都分配在第二世代,也就是说前边第 0代和第1代的垃圾收集回收的都是第OH对象,这也就解释了为何前两个世代垃圾回收中容许复制移动对象。但对于第二世代垃圾回收呢?第二代垃圾回收以后 的对象还是第二世代,其回收时并不移动仍在使用的对象,压缩空间,而只是清除垃圾对象。当一个新LOH对象建立时,它会从堆底遍历寻找LOH中可以知足要 求的内存,若是没有接着向堆顶建立(这个过程和C运行时工做原理同样,因此也存在相同的弊端,LOH堆内存有可能存在碎片)。此时若是堆顶已经超出阙值, 引起垃圾回收器回收内存空间。

         从上边讨论中咱们能够总结一下:咱们new出一对象时它要么小对象会被放入第0代,大对象会被分在LOH中,只有垃圾回收器才可以在第1代和第2代中“分配”对象,这里所说分配对象是指移动复制对象。

         以上就是垃圾回收机制,有一块最重要的一点没有讨论,就是垃圾收集器GC怎么判断该对象是垃圾对象。关于这一点能够参考连接。

性能问题

         由上边讨论咱们能够看出,自动化垃圾回收是须要付出成本的,而世代和大对象堆/小对象堆这些概念的引入是尽量的下降这一成本。但性能问题不可避免,性能 数据分析能够很好的帮助咱们了解避免些许问题,关于性能分析工具及方法请参考References中连接。

C#下非托管资源的处理--Disposable模式

         咱们上边说过,垃圾回收器只能收集托管堆的内存,但对于堆外内存好比HWnds,数据库链接,GDI句柄,safeHandle。这样就有一个问题:垃圾 收集器不会肯定地运行,其结果可能会使您的对象在上次引用以后很长时间不能被终结。若是你的对象占用了昂贵或稀少的资源(如一个数据库链接),这是不能被 接受的。为了不无休止地等待垃圾收集器运行,拥有资源的类型应该实现 IDisposable 接口,而后该类型资源的使用方会及时地释放那些资源。Joe Duff在其网站中给了相关注意细节,并提供了一种Disposable模式。能够参考一下连接了解一下,使你的程序写的更加优雅健壮。(MSDN关于 IDisposable例子中也采用这种方法)

         http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=88e62cdf-5919-4ac7-bc33-20c06ae539ae

要强调的几点

         1. 值得注意的是虽然微软目前不会移动压缩LOH,可是未来可能会,因此若是分配了大型对象并但愿确保它们位置不被移动,则应该将其固定起来。

         2. 这篇文章是基于本人理解,有可能有出入,详细信息能够参照连接,并欢迎指正。

 

References

C++

http://en.cppreference.com/w/

http://zh.wikipedia.org/wiki/C++0x

http://blog.csdn.net/zentropy/article/details/6973411

http://www.codeproject.com/Articles/71540/Explicating-the-new-C-standard-C-0x-and-its-implem#RValues http://www.codeproject.com/Articles/101886/Standard-C-Library-Changes-in-Visual-C-2010

C#

http://msdn.microsoft.com/zh-cn/magazine/bb985011(en-us).aspx

http://msdn.microsoft.com/zh-cn/magazine/cc534993.aspx

http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=88e62cdf-5919-4ac7-bc33-20c06ae539ae

性能问题和多语言交互

http://msdn.microsoft.com/zh-cn/magazine/ee309515.aspx

http://msdn.microsoft.com/zh-cn/magazine/cc163528.aspx

http://msdn.microsoft.com/zh-cn/magazine/cc163316.aspx

http://msdn.microsoft.com/zh-cn/magazine/cc163392.aspx

垃圾收集发展史:

http://blog.csdn.net/KAI3000/article/details/314628

http://blog.csdn.net/hellothere/article/details/2115422

http://blog.csdn.net/hellothere/article/details/2245734

相关文章
相关标签/搜索