• GC 垃圾回收
     .NET Framework 的垃圾回收器管理应用程序的内存分配和释放。每次您使用 new 运算符创建对象时,运行库都从托管堆为该对象分配内存。只要托管堆中有地址空间可用,运行库就会继续为新对象分配空间。但是,内存不是无限大的。最终,垃圾回收器必须执行回收以释放一些内存。垃圾回收器优化引擎根据正在进行的分配情况确定执行回收的最佳时间。当垃圾回收器执行回收时,它检查托管堆中不再被应用程序使用的对象并执行必要的操作来回收它们占用的内存。在内存大于 2GB 的服务器中,可能需要在 boot.ini 文件中指定 /3GB 开关,以避免当内存仍可供系统使用时出现明显的内存不足问题。当使用非托管资源时,需要构造一个用完后清理自身的类,这时需要编写代码来进行垃圾回收。
  • 将对象引用设置为空
     在C#中将对象引用设置为空并不意味着强制垃圾回收立即启动,唯一实现的是显示的取消了引用和之前所指向对象之间的连接,不管怎么样,这么做也不会有什么害处。
  • 应用程序根
     根就是一个存储位置,其中保存着对托管堆上一个对象的引用。在垃圾回收过程中,运行库检查堆上的对象,判断应用程序是否仍然可以访问它们,即对象是否还是有根的。
    • 根的类别
      • 全局对象的引用(C#中不允许,但CIL代码允许分配全局对象)
      • 静态对象和字段的引用
      • 应用程序代码库中的局部对象引用
      • 传递进一个方法的对象参数的引用
      • 等待被终结的对象的引用
      • 任何引用对象的CPU寄存器
  • 延迟对象初始化
     当一次实例化大量对象,会大大增加垃圾回收器的压力,但又不是所有的对象都立马需要使用,这时可以使用Lazy<>延迟对象实例化。
  • 内存管理规则
    • 使用new关键字实例化类对象分配在托管堆上,然后就不用再管它了。
    • 如果托管堆没有足够的内存来分配所请求的对象,就会进行垃圾回收。
    • 重写Finalize()唯一的原因是,C#类使用了非托管资源。
    • 如果对象支持IDisposable则总是要对任何直接创建的对象调用Dispose(),应该认为如果类设计者选择支持Dispose方法,这个类型就需要执行清除工作。
  • 强制垃圾回收
     垃圾回收 GC 类提供 GC.Collect 方法,您可以使用该方法让应用程序在一定程度上直接控制垃圾回收器。通常情况下,您应该避免调用任何回收方法,让垃圾回收器独立运行。在大多数情况下,垃圾回收器在确定执行回收的最佳时机方面更有优势。但是,在某些不常发生的情况下,强制回收可以提高应用程序的性能。当应用程序代码中某个确定的点上使用的内存量大量减少时,在这种情况下使用 GC.Collect 方法可能比较合适。例如,应用程序可能使用引用大量非托管资源的文档。当您的应用程序关闭该文档时,您完全知道已经不再需要文档曾使用的资源了。出于性能的原因,一次全部释放这些资源很有意义。
     在垃圾回收器执行回收之前,它会挂起当前正在执行的所有线程。如果不必要地多次调用 GC.Collect,这可能会造成性能问题。您还应该注意不要将调用 GC.Collect 的代码放置在程序中用户可以经常调用的点上。这可能会削弱垃圾回收器中优化引擎的作用,而垃圾回收器可以确定运行垃圾回收的最佳时间。
    • 需要强制垃圾回收的场景
      • 应用程序将进入一段代码,后者不希望被可能的垃圾回收中断。
      • 应用程序刚刚分配非常多的对象,你想尽可能多地删除已获得的内存。
  • 对象的代

CLR试图寻找不可访问对象时不会逐个检查托管堆上的每个对象,因为这样做会浪费大量的时间。为了优化这个过程,堆上的每个对象都被指定为属于某个代,代是垃圾回收器区分内存区域的逻辑视图,代的设计思路很简单,对象在堆上的存在时间约长就越应该保留。每次从0代开始检查释放内存空间,当空间不足时检查下一个代。

     对象在执行一次垃圾回收之后,会进入到下一代。也就是说如果在第一次执行垃圾回收时,存活下来的对象会进入第1代,如果在第2次垃圾回收之后该对象仍然没有被当作垃圾回收掉,它就会成为第2代对象,2代对象就是最老的对象不会在提升代数。
     当某代垃圾回收执行时,会同时执行更年轻代的垃圾回收。比如,当1代垃圾回收时会同时回收1代和0代的对象,当2代垃圾回收时会执行1代和0代的回收。
    • 第0代

没有被标记为回收的新对象,通常对象是在0代就被回收的。

    • 第1代

上次垃圾回收未被回收的对象,被标记为回收,但因为有足够的内存空间而未被删除的。1代对象是常驻内存对象和马上消亡对象之间的一个缓冲区。

    • 第2代

在一次以上的垃圾回收后仍然没有被回收的对象。

  • 大对象
     如果一个对象的大小超过85000byte,就认为这是一个大对象,这个数字是根据性能优化的经验得到的。当一个对象申请内存大小达到这个阀值,它就会被分配到大对象堆上。CLR垃圾回收器根据所占空间大小划分对象。大对象和小对象的处理方式有很大区别,比如内存碎片整理,在内存中移动大对象的成本是昂贵的。
     从代的角度看,大对象属于第2代对象,因为只有在2代回收时才会处理大对象。
     从物理存储角度看,对象分配在不同的托管堆上。一个内存分配请求就是将托管对象放到对应的托管堆上。如果对象的大小小于85000byte,它会被放置在SOH(小对象堆)上,否则会被放在LOH(大对象堆)上。   
     当触发垃圾回收时,垃圾回收器会在小对象堆做碎片整理,将存活下来的对象移动到一起。而对于大对象堆,由于移动内存的开销很大,CLR团队选择只是清除它们,将回收掉的对象组成一个列表,以便满足下次有大对象申请使用内存,相邻的垃圾对象会被合并成一块空闲的内存块。
     需要时时留意的是在.Net中不会对大对象堆做碎片整理操作,因此如果你要分配大对象并不想他们被移动,你可以使用fixed语句。
  • 大对象的回收
    • 在程序代码中调用GC.Collect方法时,如果在调用GC.Collect方法是传入GC.MaxGeneration参数时,会执行所有代对象的垃圾回收,包括大对象堆的垃圾回收。
    • CLR自动进行垃圾回收时,如果垃圾回收算法认为第2代回收是有成效的会触发第2代垃圾回收,例如操作系统内存不足时。
    • 大对象和第2代对象是一起回收的,如果大对象或者第2代对象占用空间超过其阀值时,就会触发第2代对象和大对象的回收。
  • 大对象对性能的影响
     如果是临时性的分配大对象,就需要很多的时间来运行垃圾回收,也就是说如果你持续的使用大对象然后又释放大对象对性能会有很大的负面影响。当回收大对象时又触发回收第2代对象,则对性能会产生更大的负面影响。
 

.NET 对象生命周期的更多相关文章

  1. Hibernate的三种状态及对象生命周期

        理解Hibernate的三种状态,更利于理解Hibernate的运行机制,这些可以让你在开发中对疑点问题的定位产生关键性的帮助. 三种状态 临时状态(Transient):在通过new关键字, ...

  2. .Net组件程序设计之对象生命周期

    .Net组件程序设计之对象生命周期 .NET 垃圾回收 IDisposable() Using语句 .NET 垃圾回收 是CLR管理着垃圾回收器,垃圾回收器监控着托管堆,而我们使用的对象以及系统启动是 ...

  3. Ninject之旅之三:Ninject对象生命周期

    摘要 DI容器的一个责任是管理他创建的对象的生命周期.他应该决定什么时候创建一个给定类型的对象,什么时候使用已经存在的对象.他还需要在对象不需要的时候处理对象.Ninject在不同的情况下管理对象的生 ...

  4. iOS视图控制对象生命周期

    iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...

  5. IOS 视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途

    iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...

  6. 【转】【iOS知识学习】_视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途

    原文网址:http://blog.csdn.net/weasleyqi/article/details/8090373 iOS视图控制对象生命周期-init.viewDidLoad.viewWillA ...

  7. _视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途

    iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用途 ...

  8. ASP.NET Core Web API下事件驱动型架构的实现(二):事件处理器中对象生命周期的管理

    在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发.订阅和处理的流程.这种实现太简单了,百十行代码就展示了一个基本工作原理.然而,要将这样的解决方案运用到实际生产环境,还有很 ...

  9. Python学习手册之内部方法、操作符重载和对象生命周期

    在上一篇文章中,我们介绍了 Python 的类和继承,现在我们介绍 Python 的内部方法.操作符重载和对象生命周期. 查看上一篇文章请点击:https://www.cnblogs.com/dust ...

  10. Servlet对象生命周期(四)

    一.Servlet对象生命周期 一下图片说明上图第7点 destroy()方法是在停止tomcat服务器时执行 https://pan.baidu.com/s/1mgTabWW#list/path=% ...

随机推荐

  1. C++的性能C#的产能?! - .Net Native 系列向导

    之前一文<c++的性能, c#的产能?!鱼和熊掌可以兼得,.NET NATIVE初窥> 获得很多朋友支持和鼓励,也更让我坚定做这项技术的推广者,希望能让更多的朋友了解这项技术,于是先从官方 ...

  2. MySQL mysqldump数据导出详解

    介绍 在日常维护工作当中经常会需要对数据进行导出操作,而mysqldump是导出数据过程中使用非常频繁的一个工具:它自带的功能参数非常多,文章中会列举出一些常用的操作,在文章末尾会将所有的参数详细说明 ...

  3. RTSP协议转换RTMP直播协议

    RTSP协议转换RTMP直播协议 RTSP协议也是广泛使用的直播/点播流媒体协议,最近实现了一个RTSP协议转换RTMP直播协议的程序,为的是可以接收远端设备或服务器的多路RTSP直播数据,实时转换为 ...

  4. Java接口总结

    接口的定义: 使用interface来定义一个接口.接口定义与类的定义类似,也是分为接口的声明和接口体,其中接口体由变量定义和方法定义两部分组成,定义接口的基本语法如下: [修饰符] interfac ...

  5. oracle数据库表的导入导出cmd命令大全

    在实际的项目开发中经常会遇到导入导出oracle数据库中的表,以下是常用的一些cmd命令: 一.数据表的导出 1 将数据库TEST完全导出,用户名system 密码manager 导出到D:daoch ...

  6. HTML的页面IE注释

    我们常常会在网页的HTML里面看到形如[if lte IE 9]……[endif]的代码,表示的是限定某些浏览器版本才能执行的语句,那么这些判断语句的规则是什么呢?请看下文: <!--[if ! ...

  7. ASP.NET MVC5 网站开发实践(一) - 项目框架

    前几天算是开题了,关于怎么做自己想了很多,但毕竟没做过项目既不知道这些想法有无必要,也不知道能不能实现,不过邓爷爷说过"摸着石头过河"吧.这段时间看了一些博主的文章收获很大,特别是 ...

  8. PHP+MySQL代码部署在Linux(Ubuntu)上注意事项

    最近帮同学做一个网站,同学买的是阿里云服务器,Linux发行版是Ubuntu12.04.我在本地把程序写好,都调试好了.然后他让我自己发布和部署.之前在大学里上操作系统课程时,也用过一段时间的Ubun ...

  9. 前端编码风格规范之 HTML 规范

    HTML 规范 文档类型 推荐使用 HTML5 的文档类型申明: <!DOCTYPE html>. (建议使用 text/html 格式的 HTML.避免使用 XHTML.XHTML 以及 ...

  10. 安装nginx

    [yum安装nginx] yum clean all(这步不执行会出现no more mirrors to try错误) cd /etc/yum.repos.d/ vi nginx.repo 填写 [ ...