|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Class: GC
**
**
** 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
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern int GetGCLatencyMode();
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern int SetGCLatencyMode(int newLatencyMode);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[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
[ResourceExposure(ResourceScope.None)]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
internal static extern int _EndNoGCRegion();
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern int GetLOHCompactionMode();
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern void SetLOHCompactionMode(int newLOHCompactionyMode);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern int GetGenerationWR(IntPtr handle);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern long GetTotalMemory();
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
private static extern void _Collect(int generation, int mode);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern int GetMaxGeneration();
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern int _CollectionCount (int generation, int getSpecialGCCount);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
internal static extern bool IsServerGC();
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity]
private static extern void _AddMemoryPressure(UInt64 bytesAllocated);
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[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.
//
#if FEATURE_LEGACYNETCF
[System.Security.SecurityCritical]
#else
[System.Security.SecuritySafeCritical] // auto-generated
#endif
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern int GetGeneration(Object obj);
// Forces a collection of all generations from 0 through Generation.
//
#if FEATURE_LEGACYNETCF
[System.Security.SecurityCritical] // auto-generated
#endif
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(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 ----s 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 near the end of a
// method where they must keep an object alive for the duration of that
// method, up until this method is called. 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 says 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
[ResourceExposure(ResourceScope.None)]
[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
[ResourceExposure(ResourceScope.None)]
[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
[ResourceExposure(ResourceScope.None)]
[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
[ResourceExposure(ResourceScope.None)]
[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]
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern IntPtr CreateSizedRef(Object o);
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern void FreeSizedRef(IntPtr h);
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern Object GetTargetOfSizedRef(IntPtr h);
[System.Security.SecurityCritical]
[ResourceExposure(ResourceScope.None)]
[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
}
|