gc函数

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时分配一些对象后马上就在回收。

View Code

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);
            }
        }
复制代码

执行结果:

View Code

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是其它几个类的抽象基类。它们主要用于与非托管代码进行安全的互操作。

阅读更多
换一批

没有更多推荐了,返回首页