summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/GC.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/GC.cs')
-rw-r--r--src/mscorlib/src/System/GC.cs641
1 files changed, 641 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/GC.cs b/src/mscorlib/src/System/GC.cs
new file mode 100644
index 0000000000..73c676df7d
--- /dev/null
+++ b/src/mscorlib/src/System/GC.cs
@@ -0,0 +1,641 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+**
+**
+** Purpose: Exposes features of the Garbage Collector through
+** the class libraries. This is a class which cannot be
+** instantiated.
+**
+**
+===========================================================*/
+namespace System {
+ //This class only static members and doesn't require the serializable keyword.
+
+ using System;
+ using System.Security.Permissions;
+ using System.Reflection;
+ using System.Security;
+ using System.Threading;
+ using System.Runtime;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.ConstrainedExecution;
+ using System.Globalization;
+ using System.Runtime.InteropServices;
+ using System.Runtime.Versioning;
+ using System.Diagnostics.Contracts;
+
+ [Serializable]
+ public enum GCCollectionMode
+ {
+ Default = 0,
+ Forced = 1,
+ Optimized = 2
+ }
+
+ // !!!!!!!!!!!!!!!!!!!!!!!
+ // make sure you change the def in vm\gc.h
+ // if you change this!
+ [Serializable]
+ internal enum InternalGCCollectionMode
+ {
+ NonBlocking = 0x00000001,
+ Blocking = 0x00000002,
+ Optimized = 0x00000004,
+ Compacting = 0x00000008,
+ }
+
+ // !!!!!!!!!!!!!!!!!!!!!!!
+ // make sure you change the def in vm\gc.h
+ // if you change this!
+ [Serializable]
+ public enum GCNotificationStatus
+ {
+ Succeeded = 0,
+ Failed = 1,
+ Canceled = 2,
+ Timeout = 3,
+ NotApplicable = 4
+ }
+
+ public static class GC
+ {
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern int GetGCLatencyMode();
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern int SetGCLatencyMode(int newLatencyMode);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ internal static extern int _StartNoGCRegion(long totalSize, bool lohSizeKnown, long lohSize, bool disallowFullBlockingGC);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ internal static extern int _EndNoGCRegion();
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern int GetLOHCompactionMode();
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern void SetLOHCompactionMode(int newLOHCompactionMode);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern int GetGenerationWR(IntPtr handle);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ private static extern long GetTotalMemory();
+
+ [System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ private static extern void _Collect(int generation, int mode);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern int GetMaxGeneration();
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ private static extern int _CollectionCount (int generation, int getSpecialGCCount);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern bool IsServerGC();
+
+ [System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
+ private static extern void _AddMemoryPressure(UInt64 bytesAllocated);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
+ private static extern void _RemoveMemoryPressure(UInt64 bytesAllocated);
+
+ [System.Security.SecurityCritical] // auto-generated_required
+ public static void AddMemoryPressure (long bytesAllocated) {
+ if( bytesAllocated <= 0) {
+ throw new ArgumentOutOfRangeException("bytesAllocated",
+ Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
+ }
+
+ if( (4 == IntPtr.Size) && (bytesAllocated > Int32.MaxValue) ) {
+ throw new ArgumentOutOfRangeException("pressure",
+ Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegInt32"));
+ }
+ Contract.EndContractBlock();
+
+ _AddMemoryPressure((ulong)bytesAllocated);
+ }
+
+ [System.Security.SecurityCritical] // auto-generated_required
+ public static void RemoveMemoryPressure (long bytesAllocated) {
+ if( bytesAllocated <= 0) {
+ throw new ArgumentOutOfRangeException("bytesAllocated",
+ Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
+ }
+
+ if( (4 == IntPtr.Size) && (bytesAllocated > Int32.MaxValue) ) {
+ throw new ArgumentOutOfRangeException("bytesAllocated",
+ Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegInt32"));
+ }
+ Contract.EndContractBlock();
+
+ _RemoveMemoryPressure((ulong) bytesAllocated);
+ }
+
+
+ // Returns the generation that obj is currently in.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ public static extern int GetGeneration(Object obj);
+
+
+ // Forces a collection of all generations from 0 through Generation.
+ //
+ public static void Collect(int generation) {
+ Collect(generation, GCCollectionMode.Default);
+ }
+
+ // Garbage Collect all generations.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static void Collect() {
+ //-1 says to GC all generations.
+ _Collect(-1, (int)InternalGCCollectionMode.Blocking);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static void Collect(int generation, GCCollectionMode mode)
+ {
+ Collect(generation, mode, true);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static void Collect(int generation, GCCollectionMode mode, bool blocking)
+ {
+ Collect(generation, mode, blocking, false);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static void Collect(int generation, GCCollectionMode mode, bool blocking, bool compacting)
+ {
+ if (generation<0)
+ {
+ throw new ArgumentOutOfRangeException("generation", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
+ }
+
+ if ((mode < GCCollectionMode.Default) || (mode > GCCollectionMode.Optimized))
+ {
+ throw new ArgumentOutOfRangeException("mode", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
+ }
+
+ Contract.EndContractBlock();
+
+ int iInternalModes = 0;
+
+ if (mode == GCCollectionMode.Optimized)
+ {
+ iInternalModes |= (int)InternalGCCollectionMode.Optimized;
+ }
+
+ if (compacting)
+ iInternalModes |= (int)InternalGCCollectionMode.Compacting;
+
+ if (blocking)
+ {
+ iInternalModes |= (int)InternalGCCollectionMode.Blocking;
+ }
+ else if (!compacting)
+ {
+ iInternalModes |= (int)InternalGCCollectionMode.NonBlocking;
+ }
+
+ _Collect(generation, iInternalModes);
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ public static int CollectionCount (int generation)
+ {
+ if (generation<0)
+ {
+ throw new ArgumentOutOfRangeException("generation", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
+ }
+ Contract.EndContractBlock();
+ return _CollectionCount(generation, 0);
+ }
+
+ // pass in true to get the BGC or FGC count.
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ internal static int CollectionCount (int generation, bool getSpecialGCCount)
+ {
+ if (generation<0)
+ {
+ throw new ArgumentOutOfRangeException("generation", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
+ }
+ Contract.EndContractBlock();
+ return _CollectionCount(generation, (getSpecialGCCount ? 1 : 0));
+ }
+
+ // This method DOES NOT DO ANYTHING in and of itself. It's used to
+ // prevent a finalizable object from losing any outstanding references
+ // a touch too early. The JIT is very aggressive about keeping an
+ // object's lifetime to as small a window as possible, to the point
+ // where a 'this' pointer isn't considered live in an instance method
+ // unless you read a value from the instance. So for finalizable
+ // objects that store a handle or pointer and provide a finalizer that
+ // cleans them up, this can cause subtle race conditions with the finalizer
+ // thread. This isn't just about handles - it can happen with just
+ // about any finalizable resource.
+ //
+ // Users should insert a call to this method right after the last line
+ // of their code where their code still needs the object to be kept alive.
+ // The object which reference is passed into this method will not
+ // be eligible for collection until the call to this method happens.
+ // Once the call to this method has happened the object may immediately
+ // become eligible for collection. Here is an example:
+ //
+ // "...all you really need is one object with a Finalize method, and a
+ // second object with a Close/Dispose/Done method. Such as the following
+ // contrived example:
+ //
+ // class Foo {
+ // Stream stream = ...;
+ // protected void Finalize() { stream.Close(); }
+ // void Problem() { stream.MethodThatSpansGCs(); }
+ // static void Main() { new Foo().Problem(); }
+ // }
+ //
+ //
+ // In this code, Foo will be finalized in the middle of
+ // stream.MethodThatSpansGCs, thus closing a stream still in use."
+ //
+ // If we insert a call to GC.KeepAlive(this) at the end of Problem(), then
+ // Foo doesn't get finalized and the stream stays open.
+ [MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ public static void KeepAlive(Object obj)
+ {
+ }
+
+ // Returns the generation in which wo currently resides.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static int GetGeneration(WeakReference wo) {
+ int result = GetGenerationWR(wo.m_handle);
+ KeepAlive(wo);
+ return result;
+ }
+
+ // Returns the maximum GC generation. Currently assumes only 1 heap.
+ //
+ public static int MaxGeneration {
+ [System.Security.SecuritySafeCritical] // auto-generated
+ get { return GetMaxGeneration(); }
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [SuppressUnmanagedCodeSecurity]
+ private static extern void _WaitForPendingFinalizers();
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static void WaitForPendingFinalizers() {
+ // QCalls can not be exposed from mscorlib directly, need to wrap it.
+ _WaitForPendingFinalizers();
+ }
+
+ // Indicates that the system should not call the Finalize() method on
+ // an object that would normally require this call.
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ private static extern void _SuppressFinalize(Object o);
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
+ public static void SuppressFinalize(Object obj) {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+ Contract.EndContractBlock();
+ _SuppressFinalize(obj);
+ }
+
+ // Indicates that the system should call the Finalize() method on an object
+ // for which SuppressFinalize has already been called. The other situation
+ // where calling ReRegisterForFinalize is useful is inside a finalizer that
+ // needs to resurrect itself or an object that it references.
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void _ReRegisterForFinalize(Object o);
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static void ReRegisterForFinalize(Object obj) {
+ if (obj == null)
+ throw new ArgumentNullException("obj");
+ Contract.EndContractBlock();
+ _ReRegisterForFinalize(obj);
+ }
+
+ // Returns the total number of bytes currently in use by live objects in
+ // the GC heap. This does not return the total size of the GC heap, but
+ // only the live objects in the GC heap.
+ //
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static long GetTotalMemory(bool forceFullCollection) {
+ long size = GetTotalMemory();
+ if (!forceFullCollection)
+ return size;
+ // If we force a full collection, we will run the finalizers on all
+ // existing objects and do a collection until the value stabilizes.
+ // The value is "stable" when either the value is within 5% of the
+ // previous call to GetTotalMemory, or if we have been sitting
+ // here for more than x times (we don't want to loop forever here).
+ int reps = 20; // Number of iterations
+ long newSize = size;
+ float diff;
+ do {
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+ size = newSize;
+ newSize = GetTotalMemory();
+ diff = ((float)(newSize - size)) / size;
+ } while (reps-- > 0 && !(-.05 < diff && diff < .05));
+ return newSize;
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern long _GetAllocatedBytesForCurrentThread();
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ public static long GetAllocatedBytesForCurrentThread() {
+ return _GetAllocatedBytesForCurrentThread();
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern bool _RegisterForFullGCNotification(int maxGenerationPercentage, int largeObjectHeapPercentage);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern bool _CancelFullGCNotification();
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern int _WaitForFullGCApproach(int millisecondsTimeout);
+
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern int _WaitForFullGCComplete(int millisecondsTimeout);
+
+ [SecurityCritical]
+ public static void RegisterForFullGCNotification(int maxGenerationThreshold, int largeObjectHeapThreshold)
+ {
+ if ((maxGenerationThreshold <= 0) || (maxGenerationThreshold >= 100))
+ {
+ throw new ArgumentOutOfRangeException("maxGenerationThreshold",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ Environment.GetResourceString("ArgumentOutOfRange_Bounds_Lower_Upper"),
+ 1,
+ 99));
+ }
+
+ if ((largeObjectHeapThreshold <= 0) || (largeObjectHeapThreshold >= 100))
+ {
+ throw new ArgumentOutOfRangeException("largeObjectHeapThreshold",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ Environment.GetResourceString("ArgumentOutOfRange_Bounds_Lower_Upper"),
+ 1,
+ 99));
+}
+
+ if (!_RegisterForFullGCNotification(maxGenerationThreshold, largeObjectHeapThreshold))
+ {
+ throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotWithConcurrentGC"));
+ }
+ }
+
+ [SecurityCritical]
+ public static void CancelFullGCNotification()
+ {
+ if (!_CancelFullGCNotification())
+ {
+ throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_NotWithConcurrentGC"));
+ }
+ }
+
+ [SecurityCritical]
+ public static GCNotificationStatus WaitForFullGCApproach()
+ {
+ return (GCNotificationStatus)_WaitForFullGCApproach(-1);
+ }
+
+ [SecurityCritical]
+ public static GCNotificationStatus WaitForFullGCApproach(int millisecondsTimeout)
+ {
+ if (millisecondsTimeout < -1)
+ throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+
+ return (GCNotificationStatus)_WaitForFullGCApproach(millisecondsTimeout);
+ }
+
+ [SecurityCritical]
+ public static GCNotificationStatus WaitForFullGCComplete()
+ {
+ return (GCNotificationStatus)_WaitForFullGCComplete(-1);
+ }
+
+ [SecurityCritical]
+ public static GCNotificationStatus WaitForFullGCComplete(int millisecondsTimeout)
+ {
+ if (millisecondsTimeout < -1)
+ throw new ArgumentOutOfRangeException("millisecondsTimeout", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegOrNegative1"));
+ return (GCNotificationStatus)_WaitForFullGCComplete(millisecondsTimeout);
+ }
+
+ enum StartNoGCRegionStatus
+ {
+ Succeeded = 0,
+ NotEnoughMemory = 1,
+ AmountTooLarge = 2,
+ AlreadyInProgress = 3
+ }
+
+ enum EndNoGCRegionStatus
+ {
+ Succeeded = 0,
+ NotInProgress = 1,
+ GCInduced = 2,
+ AllocationExceeded = 3
+ }
+
+ [SecurityCritical]
+ static bool StartNoGCRegionWorker(long totalSize, bool hasLohSize, long lohSize, bool disallowFullBlockingGC)
+ {
+ StartNoGCRegionStatus status = (StartNoGCRegionStatus)_StartNoGCRegion(totalSize, hasLohSize, lohSize, disallowFullBlockingGC);
+ if (status == StartNoGCRegionStatus.AmountTooLarge)
+ throw new ArgumentOutOfRangeException("totalSize",
+ "totalSize is too large. For more information about setting the maximum size, see \"Latency Modes\" in http://go.microsoft.com/fwlink/?LinkId=522706");
+ else if (status == StartNoGCRegionStatus.AlreadyInProgress)
+ throw new InvalidOperationException("The NoGCRegion mode was already in progress");
+ else if (status == StartNoGCRegionStatus.NotEnoughMemory)
+ return false;
+ return true;
+ }
+
+ [SecurityCritical]
+ public static bool TryStartNoGCRegion(long totalSize)
+ {
+ return StartNoGCRegionWorker(totalSize, false, 0, false);
+ }
+
+ [SecurityCritical]
+ public static bool TryStartNoGCRegion(long totalSize, long lohSize)
+ {
+ return StartNoGCRegionWorker(totalSize, true, lohSize, false);
+ }
+
+ [SecurityCritical]
+ public static bool TryStartNoGCRegion(long totalSize, bool disallowFullBlockingGC)
+ {
+ return StartNoGCRegionWorker(totalSize, false, 0, disallowFullBlockingGC);
+ }
+
+ [SecurityCritical]
+ public static bool TryStartNoGCRegion(long totalSize, long lohSize, bool disallowFullBlockingGC)
+ {
+ return StartNoGCRegionWorker(totalSize, true, lohSize, disallowFullBlockingGC);
+ }
+
+ [SecurityCritical]
+ static EndNoGCRegionStatus EndNoGCRegionWorker()
+ {
+ EndNoGCRegionStatus status = (EndNoGCRegionStatus)_EndNoGCRegion();
+ if (status == EndNoGCRegionStatus.NotInProgress)
+ throw new InvalidOperationException("NoGCRegion mode must be set");
+ else if (status == EndNoGCRegionStatus.GCInduced)
+ throw new InvalidOperationException("Garbage collection was induced in NoGCRegion mode");
+ else if (status == EndNoGCRegionStatus.AllocationExceeded)
+ throw new InvalidOperationException("Allocated memory exceeds specified memory for NoGCRegion mode");
+
+ return EndNoGCRegionStatus.Succeeded;
+ }
+
+ [SecurityCritical]
+ public static void EndNoGCRegion()
+ {
+ EndNoGCRegionWorker();
+ }
+ }
+
+#if !FEATURE_CORECLR
+ internal class SizedReference : IDisposable
+ {
+ [System.Security.SecurityCritical]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern IntPtr CreateSizedRef(Object o);
+
+ [System.Security.SecurityCritical]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern void FreeSizedRef(IntPtr h);
+
+ [System.Security.SecurityCritical]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern Object GetTargetOfSizedRef(IntPtr h);
+
+ [System.Security.SecurityCritical]
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ private static extern Int64 GetApproximateSizeOfSizedRef(IntPtr h);
+
+ #pragma warning disable 420
+ [System.Security.SecuritySafeCritical]
+ private void Free()
+ {
+ IntPtr temp = _handle;
+ if (temp != IntPtr.Zero &&
+ (Interlocked.CompareExchange(ref _handle, IntPtr.Zero, temp) == temp))
+ {
+ FreeSizedRef(temp);
+ }
+ }
+
+ internal volatile IntPtr _handle;
+
+ [System.Security.SecuritySafeCritical]
+ public SizedReference(Object target)
+ {
+ IntPtr temp = IntPtr.Zero;
+ temp = CreateSizedRef(target);
+ _handle = temp;
+ }
+
+ ~SizedReference()
+ {
+ Free();
+ }
+
+ public Object Target
+ {
+ [System.Security.SecuritySafeCritical]
+ get
+ {
+ IntPtr temp = _handle;
+ if (temp == IntPtr.Zero)
+ {
+ return null;
+ }
+
+ Object o = GetTargetOfSizedRef(temp);
+
+ return (_handle == IntPtr.Zero) ? null : o;
+ }
+ }
+
+ public Int64 ApproximateSize
+ {
+ [System.Security.SecuritySafeCritical]
+ get
+ {
+ IntPtr temp = _handle;
+
+ if (temp == IntPtr.Zero)
+ {
+ throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
+ }
+
+ Int64 size = GetApproximateSizeOfSizedRef(temp);
+
+ if (_handle == IntPtr.Zero)
+ {
+ throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
+ }
+ else
+ {
+ return size;
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ Free();
+ GC.SuppressFinalize(this);
+ }
+ }
+#endif
+}