找回密码
 立即注册

QQ登录

只需一步,快速开始

graper

高级会员

45

主题

63

帖子

1348

积分

高级会员

积分
1348

活字格认证

graper
高级会员   /  发表于:2009-12-17 12:01  /   查看:7126  /  回复:0
Post by "winking",  08-19-2008, 10:21
-----------------------------------------------------


Using the System.GC APIs to Improve Performance

Post at http://blogs.msdn.com/clrperfblog/archive/2008/08/18/using-the-system-gc-apis-to-improve-performance.aspx

AddMemoryPressure and RemoveMemoryPressure
The Garbage Collector (GC) handles managed memory and only managed memory.  That means it’s up to you to manage any other resources your application holds onto (files, network or database connections, etc).  AddMemoryPressure and RemoveMemoryPressure, added in .NET 2.0, are used to give a hint to the GC about the size of these unmanaged resources.  

Consider the following contrived class which holds a handle to an open file (AllocHandle and FreeHandle are made-up functions for illustration purposes):
  1. class FileHandleHolder
  2. {
  3.     protected IntPtr _fileHandle;

  4.     public FileHandleHolder(string fileName)
  5.     {
  6.        _fileHandle = AllocHandle(fileName);
  7.     }

  8.     ~FileHandleHolder()
  9.     {
  10. FreeHandle(_fileHandle);
  11.     }
  12. }
复制代码
The handle itself is an IntPtr, which takes up much less memory than the file itself.  As far as the GC is concerned, an instance of FileHandleHolder doesn’t exert much memory pressure, so the GC tunes itself accordingly.  If however, fileHandle pointed to a 1 GB file, the GC still thinks there isn’t much memory pressure caused by this class, since the file is not on the managed heap.  So how do we trick the GC into taking into account our 1 GB file?  Let’s make two small changes to our FileHandleHolder class:
  1. class FileHandleHolder
  2. {
  3.     protected IntPtr _fileHandle;

  4.     public FileHandleHolder(string filename, long fileSize)
  5.     {
  6.        _fileHandle = AllocHandle(fileName);
  7. GC.AddMemoryPressure(fileSize);
  8.     }

  9.     ~FileHandleHolder()
  10.     {
  11. FreeHandle(_fileHandle);
  12. GC.RemoveMemoryPressure(fileSize);
  13.     }
  14. }
复制代码
Our first change is to the constructor.  We can pass the size of the actual file to GC.AddMemoryPressure.  This will tell the GC that this application has an additional 1 GB of memory pressure to it, and the GC will adjust its tuning accordingly.  The second change is to the finalizer.  We call GC.RemoveMemoryPressure to tell the GC there is 1 GB less pressure.

A word of warning, make sure you balance your Add/Removes, lest you cause the GC to start collecting more aggressively and hurting your performance.

Collect
We’ve all heard the advice: don’t call GC.Collect.  It interferes with the GC’s own tuning and unless you really know what you’re doing, you can hurt your application’s overall performance.  In .NET 3.5, we added an overload to GC.Collect that takes a GCCollectionMode enum value.  In places where you think you could benefit from a call to GC.Collect (Perf Guru Rico Mariani has some advice about that here: http://blogs.msdn.com/ricom/archive/2004/11/29/271829.aspx), you can call GC.Collect(2, GCCollectionMode.Optimized), which tells the GC to use its best judgment about whether to actually do a GC.   Based on the GC’s tuning to that point, it will decide if the GC heap will benefit from a collection or not.



SuppressFinalize
Finalizers are bad for performance.  After being marked no longer reachable from user code following a collection, your finalizable object stays in memory until its finalizer is run, and only after the next collection is the memory actually reclaimed.  And not just your finalizable object, the entire object graph your object references.

To avoid the need for finalizers, we recommend implementing the Dispose Pattern (http://msdn.microsoft.com/en-us/library/fs2xkftw.aspx).  This is where GC.SuppressFinalize comes in.  Let’s consider our FileHandleHolder class again, but this time have it use the Dispose Pattern:

  1. class FileHandleHolder : IDisposable
  2. {
  3.     protected IntPtr _fileHandle;
  4.     public FileHandleHolder(string filename, long fileSize)
  5.     {
  6.        _fileHandle = AllocHandle(fileName);
  7. GC.AddMemoryPressure(fileSize);
  8.     }

  9.     ~FileHandleHolder()
  10.     {
  11. Dispose(false);
  12.     }

  13.     public void Dispose()
  14.     {
  15.        Dispose(true);
  16.        GC.SuppressFinalize(this);
  17.     }

  18.     protected virtual void Dispose(bool disposing)
  19.     {
  20. FreeHandle(_fileHandle);
  21. GC.RemoveMemoryPressure(fileSize);
  22.     }
  23. }

复制代码
Using the Dispose Pattern, the GC gets the hint that the memory pressure is removed sooner than waiting for it to be collected then finalized, and the GC can resume its tuning.  Stay tuned for my next blog post that will describe some of the new GC APIs added in .NET 3.5 SP1.

This post was authored by Chris Lyon of the CLR performance team at Microsoft Corporation.

0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部