The Labs \ Source Viewer \ SSCLI \ System \ GC

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class:  GC
  18. **
  19. **
  20. ** Purpose: Exposes features of the Garbage Collector through
  21. ** the class libraries.  This is a class which cannot be
  22. ** instantiated.
  23. **
  24. **
  25. ===========================================================*/
  26. namespace System
  27. {
  28.     //This class only static members and doesn't require the serializable keyword.
  29.    
  30.     using System;
  31.     using System.Security.Permissions;
  32.     using System.Reflection;
  33.     using System.Security;
  34.     using System.Threading;
  35.     using System.Runtime.CompilerServices;
  36.     using System.Runtime.ConstrainedExecution;
  37.     using System.Reflection.Cache;
  38.    
  39.     public static class GC
  40.     {
  41.        
  42.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  43.         private static extern int GetGenerationWR(IntPtr handle);
  44.        
  45.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  46.         private static extern long nativeGetTotalMemory();
  47.        
  48.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  49.         private static extern void nativeCollectGeneration(int generation);
  50.        
  51.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  52.         private static extern int nativeGetMaxGeneration();
  53.        
  54.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  55.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  56.         private static extern int nativeCollectionCount(int generation);
  57.        
  58.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  59.         static internal extern bool nativeIsServerGC();
  60.        
  61.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  62.         static internal extern void nativeAddMemoryPressure(UInt64 bytesAllocated);
  63.        
  64.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  65.         static internal extern void nativeRemoveMemoryPressure(UInt64 bytesAllocated);
  66.        
  67.         [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
  68.         public static void AddMemoryPressure(long bytesAllocated)
  69.         {
  70.             if (bytesAllocated <= 0) {
  71.                 throw new ArgumentOutOfRangeException("bytesAllocated", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  72.             }
  73.            
  74.             if ((4 == IntPtr.Size) && (bytesAllocated > Int32.MaxValue)) {
  75.                 throw new ArgumentOutOfRangeException("pressure", Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegInt32"));
  76.             }
  77.            
  78.             nativeAddMemoryPressure((ulong)bytesAllocated);
  79.         }
  80.        
  81.         [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
  82.         public static void RemoveMemoryPressure(long bytesAllocated)
  83.         {
  84.             if (bytesAllocated <= 0) {
  85.                 throw new ArgumentOutOfRangeException("bytesAllocated", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  86.             }
  87.            
  88.             if ((4 == IntPtr.Size) && (bytesAllocated > Int32.MaxValue)) {
  89.                 throw new ArgumentOutOfRangeException("bytesAllocated", Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegInt32"));
  90.             }
  91.            
  92.             nativeRemoveMemoryPressure((ulong)bytesAllocated);
  93.         }
  94.        
  95.        
  96.         // Returns the generation that obj is currently in.
  97.         //
  98.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  99.         public static extern int GetGeneration(object obj);
  100.        
  101.        
  102.         // Forces a collection of all generations from 0 through Generation.
  103.         //
  104.         public static void Collect(int generation)
  105.         {
  106.             if (generation < 0) {
  107.                 throw new ArgumentOutOfRangeException("generation", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
  108.             }
  109.             nativeCollectGeneration(generation);
  110.         }
  111.        
  112.         // Garbage Collect all generations.
  113.         //
  114.         public static void Collect()
  115.         {
  116.             //-1 says to GC all generations.
  117.             nativeCollectGeneration(-1);
  118.         }
  119.        
  120.        
  121.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  122.         public static int CollectionCount(int generation)
  123.         {
  124.             if (generation < 0) {
  125.                 throw new ArgumentOutOfRangeException("generation", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
  126.             }
  127.             return nativeCollectionCount(generation);
  128.            
  129.         }
  130.        
  131.        
  132.         // This method DOES NOT DO ANYTHING in and of itself. It's used to
  133.         // prevent a finalizable object from losing any outstanding references
  134.         // a touch too early. The JIT is very aggressive about keeping an
  135.         // object's lifetime to as small a window as possible, to the point
  136.         // where a 'this' pointer isn't considered live in an instance method
  137.         // unless you read a value from the instance. So for finalizable
  138.         // objects that store a handle or pointer and provide a finalizer that
  139.         // cleans them up, this can cause subtle races with the finalizer
  140.         // thread. This isn't just about handles - it can happen with just
  141.         // about any finalizable resource.
  142.         //
  143.         // Users should insert a call to this method near the end of a
  144.         // method where they must keep an object alive for the duration of that
  145.         // method, up until this method is called. Here is an example:
  146.         //
  147.         // "...all you really need is one object with a Finalize method, and a
  148.         // second object with a Close/Dispose/Done method. Such as the following
  149.         // contrived example:
  150.         //
  151.         // class Foo {
  152.         // Stream stream = ...;
  153.         // protected void Finalize() { stream.Close(); }
  154.         // void Problem() { stream.MethodThatSpansGCs(); }
  155.         // static void Main() { new Foo().Problem(); }
  156.         // }
  157.         //
  158.         //
  159.         // In this code, Foo will be finalized in the middle of
  160.         // stream.MethodThatSpansGCs, thus closing a stream still in use."
  161.         //
  162.         // If we insert a call to GC.KeepAlive(this) at the end of Problem(), then
  163.         // Foo doesn't get finalized and the stream says open.
  164.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  165.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  166.         public static extern void KeepAlive(object obj);
  167.        
  168.         // Returns the generation in which wo currently resides.
  169.         //
  170.         public static int GetGeneration(WeakReference wo)
  171.         {
  172.             int result = GetGenerationWR(wo.m_handle);
  173.             KeepAlive(wo);
  174.             return result;
  175.         }
  176.        
  177.         // Returns the maximum GC generation. Currently assumes only 1 heap.
  178.         //
  179.         public static int MaxGeneration {
  180.             get { return nativeGetMaxGeneration(); }
  181.         }
  182.        
  183.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  184.         public static extern void WaitForPendingFinalizers();
  185.        
  186.         // Indicates that the system should not call the Finalize() method on
  187.         // an object that would normally require this call.
  188.         // Has the DynamicSecurityMethodAttribute custom attribute to prevent
  189.         // inlining of the caller.
  190.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  191.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  192.         static internal extern void nativeSuppressFinalize(object o);
  193.        
  194.         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  195.         public static void SuppressFinalize(object obj)
  196.         {
  197.             if (obj == null)
  198.                 throw new ArgumentNullException("obj");
  199.             nativeSuppressFinalize(obj);
  200.         }
  201.        
  202.         // Indicates that the system should call the Finalize() method on an object
  203.         // for which SuppressFinalize has already been called. The other situation
  204.         // where calling ReRegisterForFinalize is useful is inside a finalizer that
  205.         // needs to resurrect itself or an object that it references.
  206.         // Has the DynamicSecurityMethodAttribute custom attribute to prevent
  207.         // inlining of the caller.
  208.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  209.         private static extern void nativeReRegisterForFinalize(object o);
  210.        
  211.         public static void ReRegisterForFinalize(object obj)
  212.         {
  213.             if (obj == null)
  214.                 throw new ArgumentNullException("obj");
  215.             nativeReRegisterForFinalize(obj);
  216.         }
  217.        
  218.         // Returns the total number of bytes currently in use by live objects in
  219.         // the GC heap. This does not return the total size of the GC heap, but
  220.         // only the live objects in the GC heap.
  221.         //
  222.         public static long GetTotalMemory(bool forceFullCollection)
  223.         {
  224.             long size = nativeGetTotalMemory();
  225.             if (!forceFullCollection)
  226.                 return size;
  227.             // If we force a full collection, we will run the finalizers on all
  228.             // existing objects and do a collection until the value stabilizes.
  229.             // The value is "stable" when either the value is within 5% of the
  230.             // previous call to nativeGetTotalMemory, or if we have been sitting
  231.             // here for more than x times (we don't want to loop forever here).
  232.             int reps = 20;
  233.             // Number of iterations
  234.             long newSize = size;
  235.             float diff;
  236.             do {
  237.                 GC.WaitForPendingFinalizers();
  238.                 GC.Collect();
  239.                 size = newSize;
  240.                 newSize = nativeGetTotalMemory();
  241.                 diff = ((float)(newSize - size)) / size;
  242.             }
  243.             while (reps-- > 0 && !(-0.05 < diff && diff < 0.05));
  244.             return newSize;
  245.         }
  246.        
  247.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  248.         private static extern void SetCleanupCache();
  249.        
  250.         private static ClearCacheHandler m_cacheHandler;
  251.         private static readonly object locker = new object();
  252.        
  253.         static internal event ClearCacheHandler ClearCache {
  254.             add {
  255.                 lock (locker) {
  256.                     m_cacheHandler += value;
  257.                     SetCleanupCache();
  258.                 }
  259.             }
  260.             remove {
  261.                 lock (locker)
  262.                     m_cacheHandler -= value;
  263.             }
  264.         }
  265.        
  266.         //This method is called from native code. If you update the signature, please also update
  267.         //mscorlib.h and COMUtilNative.cpp
  268.         static internal void FireCacheEvent()
  269.         {
  270.             BCLDebug.Trace("CACHE", "Called FileCacheEvent");
  271.             ClearCacheHandler handler = Interlocked.Exchange<ClearCacheHandler>(ref m_cacheHandler, null);
  272.             if (handler != null) {
  273.                 handler(null, null);
  274.             }
  275.         }
  276.     }
  277. }

Developer Fusion