[System.Security.SecurityCritical] // auto-generated_required public MemoryFailPoint(int sizeInMegabytes) { if (sizeInMegabytes <= 0) throw new ArgumentOutOfRangeException("sizeInMegabytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); Contract.EndContractBlock(); ulong size = ((ulong)sizeInMegabytes) << 20; _reservedMemory = size; // Check to see that we both have enough memory on the system // and that we have enough room within the user section of the // process's address space. Also, we need to use the GC segment // size, not the amount of memory the user wants to allocate. // Consider correcting this to reflect free memory within the GC // heap, and to check both the normal & large object heaps. ulong segmentSize = (ulong) (Math.Ceiling((double)size / GCSegmentSize) * GCSegmentSize); if (segmentSize >= TopOfMemory) throw new InsufficientMemoryException(Environment.GetResourceString("InsufficientMemory_MemFailPoint_TooBig")); ulong requestedSizeRounded = (ulong)(Math.Ceiling((double)sizeInMegabytes / MemoryCheckGranularity) * MemoryCheckGranularity); //re-convert into bytes requestedSizeRounded <<= 20; ulong availPageFile = 0; // available VM (physical + page file) ulong totalAddressSpaceFree = 0; // non-contiguous free address space // Check for available memory, with 2 attempts at getting more // memory. // Stage 0: If we don't have enough, trigger a GC. // Stage 1: If we don't have enough, try growing the swap file. // Stage 2: Update memory state, then fail or leave loop. // // (In the future, we could consider adding another stage after // Stage 0 to run finalizers. However, before doing that make sure // that we could abort this constructor when we call // GC.WaitForPendingFinalizers, noting that this method uses a CER // so it can't be aborted, and we have a critical finalizer. It // would probably work, but do some thinking first.) for(int stage = 0; stage < 3; stage++) { CheckForAvailableMemory(out availPageFile, out totalAddressSpaceFree); // If we have enough room, then skip some stages. // Note that multiple threads can still lead to a race condition for our free chunk // of address space, which can't be easily solved. ulong reserved = SharedStatics.MemoryFailPointReservedMemory; ulong segPlusReserved = segmentSize + reserved; bool overflow = segPlusReserved < segmentSize || segPlusReserved < reserved; bool needPageFile = availPageFile < (requestedSizeRounded + reserved + LowMemoryFudgeFactor) || overflow; bool needAddressSpace = totalAddressSpaceFree < segPlusReserved || overflow; // Ensure our cached amount of free address space is not stale. long now = Environment.TickCount; // Handle wraparound. if ((now > LastTimeCheckingAddressSpace + CheckThreshold || now < LastTimeCheckingAddressSpace) || LastKnownFreeAddressSpace < (long) segmentSize) { CheckForFreeAddressSpace(segmentSize, false); } bool needContiguousVASpace = (ulong) LastKnownFreeAddressSpace < segmentSize; BCLDebug.Trace("MEMORYFAILPOINT", "MemoryFailPoint: Checking for {0} MB, for allocation size of {1} MB, stage {9}. Need page file? {2} Need Address Space? {3} Need Contiguous address space? {4} Avail page file: {5} MB Total free VA space: {6} MB Contiguous free address space (found): {7} MB Space reserved via process's MemoryFailPoints: {8} MB", segmentSize >> 20, sizeInMegabytes, needPageFile, needAddressSpace, needContiguousVASpace, availPageFile >> 20, totalAddressSpaceFree >> 20, LastKnownFreeAddressSpace >> 20, reserved, stage); if (!needPageFile && !needAddressSpace && !needContiguousVASpace) break; switch(stage) { case 0: // The GC will release empty segments to the OS. This will // relieve us from having to guess whether there's // enough memory in either GC heap, and whether // internal fragmentation will prevent those // allocations from succeeding. GC.Collect(); continue; case 1: // Do this step if and only if the page file is too small. if (!needPageFile) continue; // Attempt to grow the OS's page file. Note that we ignore // any allocation routines from the host intentionally. RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // This shouldn't overflow due to the if clauses above. UIntPtr numBytes = new UIntPtr(segmentSize); unsafe { void * pMemory = Win32Native.VirtualAlloc(null, numBytes, Win32Native.MEM_COMMIT, Win32Native.PAGE_READWRITE); if (pMemory != null) { bool r = Win32Native.VirtualFree(pMemory, UIntPtr.Zero, Win32Native.MEM_RELEASE); if (!r) __Error.WinIOError(); } } } continue; case 2: // The call to CheckForAvailableMemory above updated our // state. if (needPageFile || needAddressSpace) { InsufficientMemoryException e = new InsufficientMemoryException(Environment.GetResourceString("InsufficientMemory_MemFailPoint")); #if _DEBUG e.Data["MemFailPointState"] = new MemoryFailPointState(sizeInMegabytes, segmentSize, needPageFile, needAddressSpace, needContiguousVASpace, availPageFile >> 20, totalAddressSpaceFree >> 20, LastKnownFreeAddressSpace >> 20, reserved); #endif throw e; } if (needContiguousVASpace) { InsufficientMemoryException e = new InsufficientMemoryException(Environment.GetResourceString("InsufficientMemory_MemFailPoint_VAFrag")); #if _DEBUG e.Data["MemFailPointState"] = new MemoryFailPointState(sizeInMegabytes, segmentSize, needPageFile, needAddressSpace, needContiguousVASpace, availPageFile >> 20, totalAddressSpaceFree >> 20, LastKnownFreeAddressSpace >> 20, reserved); #endif throw e; } break; default: Contract.Assert(false, "Fell through switch statement!"); break; } } // Success - we have enough room the last time we checked. // Now update our shared state in a somewhat atomic fashion // and handle a simple race condition with other MemoryFailPoint instances. AddToLastKnownFreeAddressSpace(-((long) size)); if (LastKnownFreeAddressSpace < 0) CheckForFreeAddressSpace(segmentSize, true); RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { SharedStatics.AddMemoryFailPointReservation((long) size); _mustSubtractReservation = true; } }
public unsafe MemoryFailPoint(int sizeInMegabytes) { if (sizeInMegabytes <= 0) { throw new ArgumentOutOfRangeException("sizeInMegabytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); } ulong num = ((ulong) sizeInMegabytes) << 20; this._reservedMemory = num; ulong size = (ulong) (Math.Ceiling((double) (((float) num) / ((float) GCSegmentSize))) * GCSegmentSize); if (size >= TopOfMemory) { throw new InsufficientMemoryException(Environment.GetResourceString("InsufficientMemory_MemFailPoint_TooBig")); } ulong availPageFile = 0L; ulong totalAddressSpaceFree = 0L; for (int i = 0; i < 3; i++) { CheckForAvailableMemory(out availPageFile, out totalAddressSpaceFree); ulong memoryFailPointReservedMemory = SharedStatics.MemoryFailPointReservedMemory; ulong num7 = size + memoryFailPointReservedMemory; bool flag = (num7 < size) || (num7 < memoryFailPointReservedMemory); bool flag2 = (availPageFile < (num7 + ((ulong) 0x1000000L))) || flag; bool flag3 = (totalAddressSpaceFree < num7) || flag; long tickCount = Environment.TickCount; if (((tickCount > (LastTimeCheckingAddressSpace + 0x2710L)) || (tickCount < LastTimeCheckingAddressSpace)) || (LastKnownFreeAddressSpace < size)) { CheckForFreeAddressSpace(size, false); } bool flag4 = LastKnownFreeAddressSpace < size; if ((!flag2 && !flag3) && !flag4) { break; } switch (i) { case 0: { GC.Collect(); continue; } case 1: if (!flag2) { continue; } RuntimeHelpers.PrepareConstrainedRegions(); try { continue; } finally { UIntPtr numBytes = new UIntPtr(size); void* address = Win32Native.VirtualAlloc(null, numBytes, 0x1000, 4); if ((address != null) && !Win32Native.VirtualFree(address, UIntPtr.Zero, 0x8000)) { __Error.WinIOError(); } } break; case 2: break; default: { continue; } } if (flag2 || flag3) { InsufficientMemoryException exception = new InsufficientMemoryException(Environment.GetResourceString("InsufficientMemory_MemFailPoint")); throw exception; } if (flag4) { InsufficientMemoryException exception2 = new InsufficientMemoryException(Environment.GetResourceString("InsufficientMemory_MemFailPoint_VAFrag")); throw exception2; } } Interlocked.Add(ref LastKnownFreeAddressSpace, (long) -num); if (LastKnownFreeAddressSpace < 0L) { CheckForFreeAddressSpace(size, true); } RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { SharedStatics.AddMemoryFailPointReservation((long) num); this._mustSubtractReservation = true; } }