`
piperzero
  • 浏览: 3482182 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

关于.NET垃圾回收(GC)的基本问题

 
阅读更多

.Net应用程序中很多问题都是没有正确的理解垃圾回收的工作原理而导致的,这里有一些关于GC的基本问题,如果看到问题答案心里都有数,那就请略过这篇,不然就一起来复习下吧。

  • 什么是代?
  • 什么时候发生垃圾回收?
  • 什么是大对象堆?
  • 什么是root?
  • 什么是finalizer
  • 什么是finalizequeue
  • 什么情况下会发生out ofmemory exception
  • 什么情况下要实现IDisposible接口?
  • 什么情况下用GC.Collect
  • GC有哪几种模式?

什么是代?

垃圾回收器使用了代的机制目的是提升性能,总共分为三代(Gen0, Gen1, Gen2)GC的工作机制基于以下假设,

  1. 对象越新,生存期越短
  2. 对象越老,生存期越长
  3. 回收堆的一部分比回收整个堆时间短

在应用程序的生命周期中,最近新建的对象被分配在第0代,在一次垃圾回收之后存活下来的进入下一代。这样可以使GC专注于回收最有可能存在更多可回收对象的第0(最近分配的最有可能很快被释放)

什么时候发生垃圾回收?

  1. 0代满
  2. 代码显示调用GC.Collect方法
  3. Windows报告内存不足 - CLR注册了 Win32 CreateMemoryResourceNotificationQueryMemoryResourceNotification监视系统总体内存使用情况,如果收到Window报告内存不足的通知,强行执行GC
  4. CLR卸载AppDomain
  5. CLR关闭

什么是大对象堆?

采用大对象堆是垃圾回收另外一个性能提升的策略,任何大于等于85000byte的对象都被视为大对象在特殊的大对象堆中分配。

大对象堆的回收策略

  1. 大对象堆被认为是第2代一部分,大对象堆回收时候同时回收第2
  2. 大对象堆不进行压缩操作-因为太耗时耗力

根据该策略我们可以推测如果大对象频繁的被分配将造成频繁的第2代垃圾回收(即完全垃圾回收),对性能造成较大影响。

什么是root?

静态对象

方法参数

局部变量

CPU寄存器

什么是finalizer?

大多数时候我们创建的类不包含非托管资源,因此只需要直接使用,CLR自然会判断其生命周期结束而后回收相应的托管资源。但如果我们创建了含有非托管资源的类,CLR提供了finalize机制来帮助自动释放非托管资源。

实现finalizer的语法与析构函数类似,实现了这个类似于析构函数的方式实际上被隐式转换成了重载父类的Finalize方法(object类默认提供了finalize方法)

class Car
{
    ~Car()  // destructor
    {
        // cleanup statements...
    }
}

转换后

protected override void Finalize()
{
    try
    {
        // Cleanup statements...
    }
    finally
    {
        base.Finalize();
    }
}

什么是finalizequeue?

在新建一个类的实例时,如果该类定义了Finalize方法,那么该类在构造器调用之前会将指向该对象的指针存放在一个叫finalization list中。垃圾回收时如果该对象被认定为垃圾,那么CLR会从finalizationlist中查找是否存在相应的对象指针,如果存在则将该指针移除,然后在freachable队列中加入该对象指针,CLR提供了一个高优先级的Finalizer线程来专门负责调用feachable队列中对象的finalize方法以释放资源。

什么情况下会发生out of memory exception?

在一个内存分配请求到达时,CLR发现第0代没有足够空间从而触发第0GC,如果还是没有足够的内存,CLR发起完全GC,接下来CLR尝试增大第0代大小,如果没有足够的地址空间来增大第0代大小或满足内存分配请求,就会抛出OutOfMemoryException

因此发生OutOfMemoryException的两个可能性是

  1. 虚拟地址空间耗尽
  2. 物理内存耗尽

什么情况下要实现IDisposible接口?

IDisposible最重要的目的是释放非托管资源,垃圾回收可以自动回收托管资源,但是对于程序中使用的非托管资源却一无所知,例如数据库连接,对象句柄等。

msdn中给了正确的IDisposable接口的正确实现,这个实现中最容易被误解的是protectedvirtualvoid Dispose(bool disposing)方法中布尔参数disposing的作用是什么。

参数disposing的目的是在显式调用Dispose方法或隐式调用Finalizer的情况下区别对待托管资源。在两种情况下对于非托管资源的处理是一致的,直接释放,不应该将非托管资源的释放放在if(disposing)的处理中。

为什么要区别对待托管资源?在显式调用dispose方法的时候可以保证其内部引用了托管资源未被回收,所有可以直接调用其相应的释放方法。但是finalizer被调用dispose的方法时,由于GC无法保证托管资源的释放顺序,所以在dispose方法中不应该再去访问内部的托管资源,有可能内部的托管资源已经被释放掉了。

using System;
using System.ComponentModel;
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
publicclass DisposeExample
{
    // A base class that implements IDisposable.
    // By implementing IDisposable, you are announcing that
    // instances of this type allocate scarce resources.
    publicclass MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource.
        private IntPtr handle;
        // Other managed resource this class uses.
        private Component component = new Component();
        // Track whether Dispose has been called.
        privatebool disposed = false;
// The class constructor.
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }
// Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        publicvoid Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }
// Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        protectedvirtualvoid Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }
// Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;
// Note disposing has been done.
                disposed = true;
}
        }
// Use interop to call the method necessary
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        privateexternstatic Boolean CloseHandle(IntPtr handle);
// Use C# destructor syntax for finalization code.
        // This destructor will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide destructors in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(false) is optimal in terms of
            // readability and maintainability.
            Dispose(false);
        }
    }
    publicstaticvoid Main()
    {
        // Insert code here to create
        // and use the MyResource object.
    }
}

什么情况下用GC.Collect?

大多数情况下我们都应该避免调用GC.Collect方法,让垃圾回收器自动执行,但是还是有些情况比如在某个时刻会发生一次非重复性事件导致大量的对象死亡,这个时候我们可以不依赖于垃圾回收器的自动机制,手动调用GC.Collect方法。

记住不要为了改善应用程序相应时间而调用GC.Collect,而是应该处于减少工作集的目的。

GC有哪几种模式?

工作站模式(workstation mode)

这种模式下GC假设机器上运行的其他应用程序对CPU资源要求不高,并且该模式可以使用并发或非并发的模式运行。

并发模式是默认的工作站模式,该模式下垃圾回收器分配一个额外的后台线程在应用程序运行时并发回收对象。一个线程因为分配对象造成第0代超出预算时,垃圾回收器挂起所有线程,判断需要回收哪些代,如果需要回收第2代,就会增加第0代的大小。然后应用程序恢复执行。并发回收是为了给用户更好的交互体验,适合客户端应用程序,但是同时要注意并发回收对性能有损害,使用更多地内存。

禁用并发模式的配置为

<configuration>
<runtime>
<gcConcurrentenabled="false"/>
</runtime>
</configuration>

服务器模式 (servermode)

这种模式下GC假设机器上没有运行其他应用程序,所有的CPU都可以用来进行垃圾回收操作。在这种情况下虚拟内存按照CPU数量划分区域分开对待,每个CPU上都运行一个GC线程负责回收自己的区域。

参考文档

Memory Management andGarbage Collection in the .NET Framework

http://msdn.microsoft.com/en-us/library/hh156531.aspx


分享到:
评论

相关推荐

    .NET垃圾回收器(GC)原理浅析

    主要介绍了.NET垃圾回收器(GC)原理浅析,本文先是讲解了一些基础知识如托管堆(Managed Heap)、CPU寄存器(CPU Register)、根(Roots)等,然后讲解了垃圾回收的基本原理、算法等,需要的朋友可以参考下

    【ASP.NET编程知识】.Net的GC垃圾回收原理及实现.docx

    【ASP.NET编程知识】.Net的GC垃圾回收原理及实现.docx

    .NET_C#_栈_堆_垃圾回收GC

    图文并茂的讲解了.NET(C#) 框架下的内存管理机制(堆栈、堆及垃圾回收GC)。 文档为英文文献的中文译本,全文通俗易懂。

    GC垃圾回收机制

    .net中关于GC垃圾回收机制的详细描述

    垃圾回收机制——GC

    asp.NET 4.0中垃圾回收机制 GC

    .Net的对象处理和垃圾回收

    CLR垃圾回收器根据所占空间大小划分对象。大对象和小对象的处理方式有很大区别。...要理解这个,我们需要理解.Net垃圾回收机制。  如大多人所知道的,.Net GC是按照“代”来回收的。程序中的对象共有3代,0代、1代和

    C#垃圾回收机制GC

    GC的前世与今生 什么是GC 一、Mark-Compact 标记压缩算法 二、 Generational 分代算法 三、Finalization Queue和Freachable Queue 托管资源 and 非托管资源: .NET的GC机制有这样两个问题. GC 10个注意事项:

    C++垃圾回收器

    在C++程序中进行垃圾回收的代码,使用标记-回收算法,支持多继承,对象数组的回收。详细的介绍在我的blog http://blog.csdn.net/winux/archive/2007/09/01/1768777.aspx

    c#如何用好垃圾回收机制GC

    一、为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1、为对应的资源分配内存 2、初始化内存 3、使用资源 4、清理资源 5、释放内存 应用程序对资源(内存使用)管理的方式,常见的一般有如下几种: 1...

    API for Boehm Garbage Collector DLL

    自动垃圾回收虽然会对性能造成一定的影响,但在大对对性能要求不是特别苛刻的场合下,使用自动垃圾回收技术可以极大的方便软件开发,降低由内存泄漏所引发的问题。 C++的自动垃圾回收库早就有了几个,商业和非商业的...

    .net 程序性能测试软件

    2、强制垃圾回收 3、多dispose,close 4、用timer,每几秒钟调用:SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);具体见附录。 5、发布的时候选择Release 6、注意代码编写时少产生...

    详谈.net中的垃圾回收机制

    1. 自动内存管理和GC 在原始程序中堆的内存分配是这样的:找到第一个有足够空间的内存地址(没被占用的),然后将该内存分配。当程序不再需要此内存中的信息时程序员需要手动将此内存释放。堆的内存是公用的,也...

    C#内存管理变化.pdf

    尽管在.net framework中我们不太需要关注内存管理和垃圾回收这方面的问题,但是出于提高我们应用程序性能的目的,在我们的脑子里还是需要有这方面的意识。明白内存管理的基本行为将有助于我们解释我们程序中变量是...

    C#技术漫谈之垃圾回收机制(GC)

    虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久。早在1958年,由鼎鼎大名的图林奖得主JohnMcCarthy所实现的Lisp语言就已经提供了GC的功能,这是GC的第一次出现。Lisp的程序员认为内存管理太重要了,...

    详解C#中的定时器Timer类及其垃圾回收机制

    主要介绍了C#中的定时器Timer类及其垃圾回收机制,讲解了Timer相关的单线程异步工作,需要的朋友可以参考下

    5到10年.NET高级面试资料总结,面试必考!!!

    8.GC垃圾回收 9.泛型 10.反射 11.死锁 12.内存泄漏 13.数据结构 二、设计方面: 1.面向对象基础 2.设计模式 3.EF 4.MVC 5.MVVM 6.IOC 三、架构框架: 1.框架 2.分布式 3.微服务 四、数据库: 1.SQL 2.事务 3....

    prometheus-net.DotNetRuntime:使用prometheus-net包公开.NET核心运行时指标(GC,JIT,锁争用,线程池)

    垃圾回收的收集频率和时间(按生成/类型,暂停时间和GC CPU消耗率) 堆大小 大小对象堆分配的字节 JIT编译和JIT CPU消耗率 线程池大小,调度延迟以及增长/缩小的原因 锁争用 抛出异常,按类型细分 这些指标对于...

Global site tag (gtag.js) - Google Analytics