这两个方法主要用于本地资源,比如一个位图占用了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时分配一些对象后马上就在回收。
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
这个也是用于本地资源的类。主要用于本地资源数量有限,如果长时间无效而未得到垃圾清理可能会导致请求失败。这个类有计数器的功能,当超过给定的初始值时,垃圾回收器就强制执行垃圾回收。
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); } }
执行结果:
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
这个类用于预测需求大量内存的操作能否成功,个人感觉很有用。它构造函数的参数是需要的内存量,单位是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); } }
public enum GCCollectionMode
{
Default = 0, //目前和Forced等效,强制回收
Forced = 1, //强制回收
Optimized = 2,//只有能释放大量内存或能减少碎片化的前提下,才执行回收
}
我们经常可能看到如下代码:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
这三句的作用是:强制回收,等待Finalize执行完毕,再次强制回收(因为Finalize的那些对象只有下次垃圾回收才真正回收,所以这里要再调一次)
下面是一个综合示例:
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.
其中SafeHandle是其它几个类的抽象基类。它们主要用于与非托管代码进行安全的互操作。