代码改变世界

.net垃圾回收学习[NET 2.0 Performance Guidelines - Garbage Collection][翻译加学习]

2011-08-28 11:35  一一九九  阅读(307)  评论(0编辑  收藏  举报

From:http://www.guidanceshare.com/wiki/.NET_2.0_Performance_Guidelines_-_Garbage_Collection

目录:

  1. Identify and analyze your application’s allocation profile
  2. Avoid Calling Gc.Coollect
  3. Consider Using Weak References with Cached Data
  4. Prevent the promotion of Short-Lived Objects
  5. Set Unneeded Member Variables to Null before making long-runing calls
  6. Minmize Hidden Allocations
  7. Avoid or Minimize Complex Object Graphs
  8. Avoid preallocating and Chunking memory

Identiy and Analyze your Application’s Allocation profile


程序内存分配性能(allocation profile)取决于以下三个因素:对象的大小、对象的数量和对象的生命周期。 当内存分配非常快的时候,GC的效率取决于在哪个代上进行回收操作。GC在GEN 0 上回收小对象是效率最高的。因为Gen 0上的对象通常是最小的也最可能在CPU缓存中的。相反,在GEN 2上经常性的回收对象则是代价昂贵的。你可以使用CLR profiler类似allocation profiler来观察你的Application的allocation patterns, 识别对象什么时候被分配,处在哪个Generation中,通过这些来优化效率。

For more information, see "How To: Use CLR Profiler" at http://msdn.microsoft.com/library/en-us/dnpag/html/scalenethowto13.asp

Avoid Calling Gc.Collect


默认的GC.Collect方法会导致回收所有代上的垃圾。对所有的代进行回收是代价昂贵的,因为系统中的理论上存活的所有对象都需要被遍历一遍比便确保完整的回收。不需要多说,尽可能的遍历所有的对象经常会消耗大量的时间。GC的算法一般都进行了一定程度的优化,确保只有当值的进行完整的Collection的时候才进行这种操作,所以,不要直接的调用GC.Collect, 让垃圾收集器决定何时需要去运行。

垃圾收集器设计的时候加入了自我优化的算法,它会根据你的应用程序对内存的需要进行算法调整。手动的强制进行垃圾回收会阻碍垃圾收集器的优化。

假如你有一个不得不需要调用GC.Collect的场景,考虑一下几点:

  • 在调用GC.Collect之后调用GC.WaitForPendingFinlizers。这回确保当前的线程等待所有对象的Finalizer都被调用后再执行。
  • 在finalizers运行后,有许多的Dead Object需要进行回收。再次调用GC.Collect收集这些对象。
System.GC.Collect(); // This gets rid of the dead objects
System.GC.WaitForPendingFinalizers(); // This waits for any finalizers to finish.
System.GC.Collect(); 
// This releases the memory associated with the objects that were just finalized.

Consider Using Weak References with Cached Data


当你使用缓存数据的时候,考虑使用weak references,  这样缓存的对象很容易根据需要复活或者当有内存压力的时候能够被GC释放掉。你不应该在小对象上大量的使用weak references, 因为这会导致weak reference自己会过载。weak reference 比较适合存储在集合中的中型或者大型的对象。

考虑如下场景: 你在你的应用程序中维护了一个雇员信息的自定义的缓存方案。通过weakreference来持有你的对象,当内存压力增大的时候对象会被回收掉。假如在随后的对象查找中,你找不到这个对象,重新从一个合法的持久源中创建这个对象。通过这种方式能够平衡缓存的使用和持久化的需要。以下代码展示了如何使用一个weak reference.

void SomeMethod() 
{
  // Create a collection
  ArrayList arr = new ArrayList(5);
  // Create a custom object
  MyObject mo = new MyObject();
  // Create a WeakReference object from the custom object
  WeakReference wk = new WeakReference(mo);
  // Add the WeakReference object to the collection
  arr.Add(wk);
  // Retrieve the weak reference
  WeakReference weakReference = (WeakReference)arr[0];
  MyObject mob = null;
  if( weakReference.IsAlive ){
    mob = (MyOBject)weakReference.Target;
  }
  if(mob==null){
    // Resurrect the object as it has been garbage collected
  }
  //continue because we have the object
}

Prevent the Promotion of Short-Lived Objects


在GEN 0上被分配和回收的对象是short-lived objects. 下面的原则确保你的short-lived对象没有被提升生命周期。

    • 不要从long-lived对象引用short-lived对象。常见的例子是将一个局部变量赋值为一个类级别的对象引用。
class Customer{
  Order _lastOrder;
  void insertOrder (int ID, int quantity, double amount, int productID){
    Order currentOrder = new Order(ID, quantity, amount, productID);
    currentOrder.Insert();
    this._lastOrder = currentOrder;
  }
}

避免这种类型的代码,因为有可能将对象的生命周期从Gen 0提升, 从而推迟了将要被回收的对象资源。一个可能避免这种情况的实现如下:

class Customer{
  int _lastOrderID;
  void ProcessOrder (int ID, int quantity, double amount, int productID){
    . . .
    this._lastOrderID = ID;
    . . .
  }
}

具体的Order Class通过ID来引用。

  • 避免实现finalize方法。 为了优化Finalization操作,GC一定会将finalizable对象提升到更老的代际,将对象变成了long-lived objects.
  • 避免finalizable对象引用其他对象。这会导致被引用的对象变成long-lived的。

References

For more information about garbage collection, see the following resources: