在应用程序代码内实例化一个类或结构时,只要有代码引用它,就会形成强引用.这意味着垃圾回收器不会清理这样的对象使用的内存.但是如果当这个对象很大,并且不经常访问时,此时可以创建对象的弱引用,弱引用允许创建和使用对象,但是垃圾回收器 运行时,就会回收对象并释放内存.
弱引用是使用WeakReference类创建的.因为对象可能在任何时刻被回收,所以在引用该对象前必须确认它存在.
using System; namespace ConsoleAppDemo { class MathTest { public int Value { get; set; } public int GetSquare() { return this.Value * this.Value; } } class Program { static void Main(string[] args) { WeakReference mathReference = new WeakReference(new MathTest()); MathTest math; if (mathReference.IsAlive) { math = mathReference.Target as MathTest; math.Value = 30; Console.WriteLine("Value field of math variable contains " + math.Value); Console.WriteLine("Square of 30 is " + math.GetSquare()); } else { Console.WriteLine("Reference is not avaliable."); } GC.Collect(); if (mathReference.IsAlive) { math = mathReference.Target as MathTest; Console.WriteLine("Value field of math variable contains " + math.Value); } else { Console.WriteLine("Reference is not available."); } } } }
.NET框架提供了另一有趣的特色,被用于实现多样的高速缓存。在.NET中弱引用通过System.WeakReference类实现。弱引用为引用的对象提供一项机制,使被引用的对象能够被垃圾收集器作用。ASP.NET高速缓存就使用了弱引用。如果内存使用率太高,高速缓存将被清除。
强制垃圾收集 .NET框架为开发者提供System.GC类来控制垃圾收集器的一些方面。垃圾收集可以通过调用GC.Collect方法强制执行。通常建议不要手动的调用垃圾收集器,而将其设置为自动方式。在某些情况下,开发者会发现强制垃圾收集将推进性能。但是,使用这个方法需要非常小心,因为在垃圾收集器运行时将延缓当前执行的线程。GC.Collect方法不应位于可能被经常调用的地方。这样做将使应用程序的性能降级。
构造函数:
WeakReference 初始化 WeakReference 类的新实例。 此构造函数重载不能在基于 Silverlight 的应用程序中实现。
WeakReference(Object) 引用指定的对象初始化 WeakReference 类的新实例。
WeakReference(Object, Boolean) 初始化 WeakReference 类的新实例,引用指定的对象并使用指定的复活跟踪。
属性:
IsAlive 获取当前 WeakReference 对象引用的对象是否已被垃圾回收的指示。
Target 获取或设置当前 WeakReference 对象引用的对象(目标)。
TrackResurrection 获取当前 WeakReference 对象引用的对象在终止后是否会被跟踪的指示。
我们考虑使用弱引用的时候:
对象稍后可能被使用,但不是很确定。(如果确定要使用,就应该用强引用)
如果需要,对象可以重新被构造出来(比如数据库构造)。
对象占相对比较大的内存(一般大于几KB以上)
在某些场合,例如缓存某些大数据对象的时候,会遇到内存与时间的两难境况,如果让大对象过快的过期,那么每次创建对象会消耗过多的性能,反之,保持了过多的大对象,那
么内存将耗尽,反而降低速度。 如果内存尚且足够,那么GC就不会回收大对象占用的内存,那么弱引用就是可到达的,也就是说可以重用这个对象,达到缓存的目的。如果内存不足,那么GC就会不得不去回收那些大对象,从而释放内存空间。
下面的代码示例演示如何使用弱引用将对象的缓存作为应用程序的资源进行维护。 此缓存是使用以索引值为关键字的 WeakReference 对象的 IDictionary(Of TKey, TValue) 构建的。 WeakReference 对象的 Target 属性是一个表示数据的字节数组中的对象。
此示例将随机访问缓存中的对象。 如果通过垃圾回收来回收对象,则将重新生成新的数据对象;否则,该对象会因弱引用而可访问。
Cache:
using System; using System.Collections.Generic; namespace ConsoleAppDemo { public class Cache { // Dictionary to contain the cache. static Dictionary<int, WeakReference> _cache; // Track the number of times an // object is regenerated. int regenCount = 0; public Cache(int count) { _cache = new Dictionary<int, WeakReference>(); // Add data objects with a // short weak reference to the cache. for (int i = 0; i < count; i++) { _cache.Add(i, new WeakReference(new Data(i), false)); } } // Returns the number of items in the cache. public int Count { get { return _cache.Count; } } // Returns the number of times an // object had to be regenerated. public int RegenerationCount { get { return regenCount; } } // Accesses a data object from the cache. // If the object was reclaimed for garbage collection, // create a new data object at that index location. public Data this[int index] { get { // Obtain an instance of a data // object from the cache of // of weak reference objects. Data d = _cache[index].Target as Data; if (d == null) { // Object was reclaimed, so generate a new one. Console.WriteLine("Regenerate object at {0}: Yes", index.ToString()); d = new Data(index); regenCount++; } else { // Object was obtained with the weak reference. Console.WriteLine("Regenerate object at {0}: No", index.ToString()); } return d; } } } }
Data:
namespace ConsoleAppDemo { // This class creates byte arrays to simulate data. public class Data { private byte[] _data; private string _name; public Data(int size) { _data = new byte[size * 1024]; _name = size.ToString(); } // Simple property. public string Name { get { return _name; } } } }
Program:
using System; namespace ConsoleApp { class Program { static void Main(string[] args) { // Create the cache. int cacheSize = 50; Random r = new Random(); Cache c = new Cache(cacheSize); string DataName = ""; // Randomly access objects in the cache. for (int i = 0; i < c.Count; i++) { int index = r.Next(c.Count); #region 注意这里的代码 如果屏蔽了 就是全部是 yes 没有 就有50%的yes if (i == 24) GC.Collect(); #endregion // Access the object by // getting a property value. DataName = c[index].Name; } // Show results. double regenPercent = c.RegenerationCount * 100 / c.Count; Console.WriteLine("Cache size: {0}, Regenerated: {1}%", c.Count.ToString(), regenPercent.ToString()); } } }