• 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. SQL Server表分区的NULL值问题

    SQL Server表分区的NULL值问题 SQL Server表分区只支持range分区这一种类型,但是本人觉得已经够用了 虽然MySQL支持四种分区类型:RANGE分区.LIST分区.HASH分区 ...

  2. .net core 学习

    资源: https://github.com/aspnet/home https://github.com/dotnet/cli

  3. Python----reduce原来是这样用的

    官方解释: Apply function of two arguments cumulatively to the items of iterable, from left to right, so ...

  4. [ASP.NET MVC 大牛之路]03 - C#高级知识点概要(2) - 线程和并发

    本人博客已转移至:http://www.exblr.com/liam  我也想过跳过C#高级知识点概要直接讲MVC,但经过前思后想,还是觉得有必要讲的.我希望通过自己的经验给大家一些指引,带着大家一起 ...

  5. Java 网络爬虫获取页面源代码

    原博文:http://www.cnblogs.com/xudong-bupt/archive/2013/03/20/2971893.html 1.网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网 ...

  6. MySQL常用命令和常见问题

    MySQL常用命令和常见问题 --创建数据库并设置字符集 create database wip default character set utf8 collate utf8_general_ci; ...

  7. 字典 Key值转换为数组

    public static string[] GetCategories() { Dictionary<string, int> itemMap = new Dictionary<s ...

  8. OpenCASCADE Camera

    OpenCASCADE Camera eryar@163.com Abstract. OpenCASCADE introduce a new class Graphic3d_Camera for th ...

  9. EntityFramework之摸索EF底层(八)

    前言 此篇文章我将深入去摸索edmx中一些不为人知的东西,有时候我们需要知道Code  First模型中一些存储以及映射的原理,个人觉得那是必要的也是有用的,因为很有可能SQL会出现一些其他问题,只有 ...

  10. Python补充06 Python之道

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! Python有一个彩蛋,用下面语句调出: import this 该彩蛋的文档记录 ...