GC垃圾回收——有用的函数和类

时间:2021-03-21 00:01:52

1,AddMemoryPressure和RemoveMemoryPressure

    这两个方法主要用于本地资源,比如一个位图占用了50M本地内存,但是托管对象只包含一个HBitMap(4字节或8字节)。但CRL并不知道这个内存压力,它可能允许你分配数百个位图,因为它们占用的托管内存太少了。这两个方法的目的就是要告诉GC它实际的本地资源用了多少内存量,GC知道这个信息后会调整它的垃圾回收策略,当压力变大时,他就强制执行垃圾回收。

        private void MemoryPressureDemo(int size)
        {
            //创建一组对象,并指定它们的逻辑大小
            for (var i = 0; i < 15; i++)
            {
                new BigNativeResource(size);
            }
            //为了演示,强制回收前面的这一组对象
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        private sealed class BigNativeResource
        {
            private int m_size;
            public BigNativeResource(int size)
            {
                m_size = size;
                if (m_size > 0)
                {
                    GC.AddMemoryPressure(size);//让垃圾回收器认为对象在物理上比较大 
                }
                Console.WriteLine("BigNativeResource create");
            }

            ~BigNativeResource()
            {
                if (m_size > 0)
                {
                    GC.RemoveMemoryPressure(m_size);//让垃圾回收器认为释放了更多的内存 
                }
                Console.WriteLine("BigNativeResource destroy");
            }
        }

测试代码如下:

        private void TestFunc()
        {
            Console.WriteLine("MemoryPressureDemo size=0");
            MemoryPressureDemo(0);//0导致垃圾回收器不频发

            Console.WriteLine("MemoryPressureDemo size=" + (10 * 1024 * 1024));
            MemoryPressureDemo(10 * 1024 * 1024);//10M 导致频繁的垃圾回收
        }

结果可以看出,10M时分配一些对象后马上就在回收。

GC垃圾回收——有用的函数和类GC垃圾回收——有用的函数和类View Code
MemoryPressureDemo size=0
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy

MemoryPressureDemo size=10485760
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource destroy
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource create
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource destroy
BigNativeResource create
BigNativeResource destroy
BigNativeResource destroy

2,HandleCollector

   这个也是用于本地资源的类。主要用于本地资源数量有限,如果长时间无效而未得到垃圾清理可能会导致请求失败。这个类有计数器的功能,当超过给定的初始值时,垃圾回收器就强制执行垃圾回收。

        private void HandeCollectorDemo()
        {
            Console.WriteLine("HandeCollectorDemo");
            for (var i = 0; i < 10; i++)
            {
                new LimitedResource();
            }
            //出于演示,强制垃圾回收
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        private sealed class LimitedResource
        {
            //创建一个HandleCollector,告诉它有2个或更多的这样的对象存在于堆中,就执行垃圾回收
            private static HandleCollector s_hc = new HandleCollector("LimitedResource", 2);

            public LimitedResource()
            {
                s_hc.Add();//告诉HandleCollector,堆中又增加了一个LimitedResource对象
                Console.WriteLine("LimitedResource create. Count={0}", s_hc.Count);
            }

            ~LimitedResource()
            {
                s_hc.Remove();//告诉HandleCollector,已经从堆中移除了一个LimitedResource对象
                Console.WriteLine("LimitedResource destroy. Count={0}", s_hc.Count);
            }
        }

执行结果:

GC垃圾回收——有用的函数和类GC垃圾回收——有用的函数和类View Code
HandeCollectorDemo
LimitedResource create. Count=1
LimitedResource create. Count=2
LimitedResource create. Count=3
LimitedResource destroy. Count=3
LimitedResource destroy. Count=2
LimitedResource destroy. Count=1
LimitedResource create. Count=1
LimitedResource create. Count=2
LimitedResource create. Count=3
LimitedResource destroy. Count=2
LimitedResource create. Count=3
LimitedResource destroy. Count=3
LimitedResource destroy. Count=2
LimitedResource destroy. Count=1
LimitedResource create. Count=1
LimitedResource create. Count=2
LimitedResource create. Count=3
LimitedResource destroy. Count=2
LimitedResource destroy. Count=1
LimitedResource destroy. Count=0

3,System.Runtime.MemoryFailPoint类

   这个类用于预测需求大量内存的操作能否成功,个人感觉很有用。它构造函数的参数是需要的内存量,单位是Mb。如果需要的内存不能请求成功,会抛出一个InsufficientMemoryException异常,这个异常继承自OutOfMemoryException异常,可以通过捕捉它来进行判断。

        private void MemoryRequestDemo()
        {
            try
            {
                //逻辑上保留1.5G 的空间
                using (System.Runtime.MemoryFailPoint mfp = new System.Runtime.MemoryFailPoint(1500))
                {
                    //在这里执行内存消耗大的算法

                }//Dispose方法逻辑上释放这1.5G内存
            }
            catch (InsufficientMemoryException e)
            {
                //无法保留所需的内存
                Console.WriteLine(e);
            }
        }

4,编程控制相关的垃圾回收函数

  • public static void Collect(); //回收全部
  • public static void Collect(int generation);//回收指定的代
  • public static void Collect(int generation, GCCollectionMode mode)//回收指定的代,Mode一般应选择Optimized

public enum GCCollectionMode

{

        Default = 0,   //目前和Forced等效,强制回收

        Forced = 1,    //强制回收

        Optimized = 2,//只有能释放大量内存或能减少碎片化的前提下,才执行回收

}

  • public static void WaitForPendingFinalizers();//挂起调用线程,直到freachable情况,完成对每个对象的Finalize方法调用。

我们经常可能看到如下代码:

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

这三句的作用是:强制回收,等待Finalize执行完毕,再次强制回收(因为Finalize的那些对象只有下次垃圾回收才真正回收,所以这里要再调一次)

  • RegisterForFullGCNotification,WaitForFullGCApproach,WaitForFullGCComplete,CancelFullGCNotification这几个方法是关于垃圾回收通知的,一般情况下,用的较少,可以参见MSDN的专题:http://technet.microsoft.com/zh-cn/library/cc713687.aspx
  • public static int GetGeneration(object obj); //获取对象的代
  • public static int GetGeneration(WeakReference wo);//获取一个弱引用对象的代
  • public static long GetTotalMemory(bool forceFullCollection);//获取托管应用程序的内存大小
  • public static void KeepAlive(object obj);//保持对象不被垃圾回收直到单前代码
  • public static int CollectionCount(int generation);//进程启动后,取得特定代上执行的垃圾回收次数

下面是一个综合示例:

  private class Genobj
        {
            ~Genobj()
            {
                Console.WriteLine("In Finalize Mehtod.");
            }
        }
        private void GCMehtodDemo()
        {
            Console.WriteLine("MaxGeneration={0}", GC.MaxGeneration);
            Genobj o = new Genobj();
            
            Console.WriteLine("o in Gen " + GC.GetGeneration(o));//0

            //force collecton
            GC.Collect();
            Console.WriteLine("o in Gen " + GC.GetGeneration(o));//1

            GC.Collect();
            Console.WriteLine("o in Gen " + GC.GetGeneration(o));//2

            o = null;//

            Console.WriteLine("collecting gen 0");
            GC.Collect(0);
            GC.WaitForPendingFinalizers();

            Console.WriteLine("collecting gen 1");
            GC.Collect(1);
            GC.WaitForPendingFinalizers();

            Console.WriteLine("collecting gen 2");
            GC.Collect(2);
            GC.WaitForPendingFinalizers();
        }

运行结果:

MaxGeneration=2
o in Gen 0
o in Gen 1
o in Gen 2
collecting gen 0
collecting gen 1
collecting gen 2
In Finalize Mehtod.

5,另外值得关注的几个类

  • GCHandle:可用于手动监视对象的生命期。
  • WeakReference:它实际是GCHandle的一个包装类,使用它时无需特权,它是弱引用,所有不支持GCHandleType的Normal或Pinned值。
  • SafeHandle,SafeFileHandle,SafeWaitHandle,SafeBuffer,SafeRegistryHandle。

        其中SafeHandle是其它几个类的抽象基类。它们主要用于与非托管代码进行安全的互操作。