MemoryFailPoint 類別

定義

在執行作業前檢查記憶體資源是否足夠。 此類別無法獲得繼承。

public ref class MemoryFailPoint sealed : System::Runtime::ConstrainedExecution::CriticalFinalizerObject, IDisposable
public sealed class MemoryFailPoint : System.Runtime.ConstrainedExecution.CriticalFinalizerObject, IDisposable
type MemoryFailPoint = class
    inherit CriticalFinalizerObject
    interface IDisposable
Public NotInheritable Class MemoryFailPoint
Inherits CriticalFinalizerObject
Implements IDisposable
繼承
實作

範例

MemoryFailPoint 可讓應用程式自行變慢,以避免以損毀的方式用盡記憶體。 它應該在語彙範圍內使用。 下列範例會啟動執行緒來處理工作佇列中的專案。 啟動每個執行緒之前,會使用 MemoryFailPoint 來檢查可用的記憶體資源。 如果擲回例外狀況,main 方法會等到記憶體可用,再啟動下一個執行緒。

using System;
using System.Runtime;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using System.Collections;

class MemoryFailPointExample
{
    // Allocate in chunks of 64 megabytes.
    private const uint chunkSize = 64 << 20;
    // Use more than the total user-available address space (on 32 bit machines)
    // to drive towards getting an InsufficientMemoryException.
    private const uint numWorkItems = 1 + ((1U << 31) / chunkSize);
    static Queue workQueue = new Queue(50);

    // This value can be computed separately and hard-coded into the application.
    // The method is included to illustrate the technique.
    private static int EstimateMemoryUsageInMB()
    {
        int memUsageInMB = 0;

        long memBefore = GC.GetTotalMemory(true);
        int numGen0Collections = GC.CollectionCount(0);
        // Execute a test version of the method to estimate memory requirements.
        // This test method only exists to determine the memory requirements.
        ThreadMethod();
        // Includes garbage generated by the worker function.
        long memAfter = GC.GetTotalMemory(false);
        // If a garbage collection occurs during the measuring, you might need a greater memory requirement.
        Console.WriteLine("Did a GC occur while measuring?  {0}", numGen0Collections == GC.CollectionCount(0));
        // Set the field used as the parameter for the MemoryFailPoint constructor.
        long memUsage = (memAfter - memBefore);
        if (memUsage < 0)
        {
            Console.WriteLine("GC's occurred while measuring memory usage.  Try measuring again.");
            memUsage = 1 << 20;
        }

        // Round up to the nearest MB.
        memUsageInMB = (int)(1 + (memUsage >> 20));
        Console.WriteLine("Memory usage estimate: {0} bytes, rounded to {1} MB", memUsage, memUsageInMB);
        return memUsageInMB;
    }

    static void Main()
    {
        Console.WriteLine("Attempts to allocate more than 2 GB of memory across worker threads.");
        int memUsageInMB = EstimateMemoryUsageInMB();

        // For a production application consider using the threadpool instead.
        Thread[] threads = new Thread[numWorkItems];
        // Create a work queue to be processed by multiple threads.
        int n = 0;
        for (n = 0; n < numWorkItems; n++)
            workQueue.Enqueue(n);
        // Continue to launch threads until the work queue is empty.
        while (workQueue.Count > 0)
        {
            Console.WriteLine(" GC heap (live + garbage): {0} MB", GC.GetTotalMemory(false) >> 20);
            MemoryFailPoint memFailPoint = null;
            try
            {
                // Check for available memory.
                memFailPoint = new MemoryFailPoint(memUsageInMB);
                n = (int)workQueue.Dequeue();
                threads[n] =
                    new Thread(new ParameterizedThreadStart(ThreadMethod));
                WorkerState state = new WorkerState(n, memFailPoint);
                threads[n].Start(state);
                Thread.Sleep(10);
            }
            catch (InsufficientMemoryException e)
            {
                // MemoryFailPoint threw an exception, handle by sleeping for a while,  then
                // continue processing the queue.
                Console.WriteLine("Expected InsufficientMemoryException thrown.  Message: " + e.Message);
                // We could optionally sleep until a running worker thread
                // has finished, like this:  threads[joinCount++].Join();
                Thread.Sleep(1000);
            }
        }

        Console.WriteLine("WorkQueue is empty - blocking to ensure all threads quit (each thread sleeps for 10 seconds)");
        foreach (Thread t in threads)
            t.Join();
        Console.WriteLine("All worker threads are finished - exiting application.");
    }

    // Test version of the working code to determine memory requirements.
    static void ThreadMethod()
    {
        byte[] bytes = new byte[chunkSize];
    }

    internal class WorkerState
    {
        internal int _threadNumber;
        internal MemoryFailPoint _memFailPoint;

        internal WorkerState(int threadNumber, MemoryFailPoint memoryFailPoint)
        {
            _threadNumber = threadNumber;
            _memFailPoint = memoryFailPoint;
        }

        internal int ThreadNumber
        {
            get { return _threadNumber; }
        }

        internal MemoryFailPoint MemoryFailPoint
        {
            get { return _memFailPoint; }
        }
    }

    // The method that does the work.
    static void ThreadMethod(Object o)
    {
        WorkerState state = (WorkerState)o;
        Console.WriteLine("Executing ThreadMethod, " +
            "thread number {0}.", state.ThreadNumber);
        byte[] bytes = null;
        try
        {
            bytes = new byte[chunkSize];
            // Allocated all the memory needed for this workitem.
            // Now dispose of the MemoryFailPoint, then process the workitem.
            state.MemoryFailPoint.Dispose();
        }
        catch (OutOfMemoryException oom)
        {
            Console.Beep();
            Console.WriteLine("Unexpected OutOfMemory exception thrown: " + oom);
        }

        // Do work here, possibly taking a lock if this app needs
        // synchronization between worker threads and/or the main thread.

        // Keep the thread alive for awhile to simulate a running thread.
        Thread.Sleep(10000);

        // A real thread would use the byte[], but to be an illustrative sample,
        // explicitly keep the byte[] alive to help exhaust the memory.
        GC.KeepAlive(bytes);
        Console.WriteLine("Thread {0} is finished.", state.ThreadNumber);
    }
}

備註

注意

此類別適用于進階開發。

建立 類別的 MemoryFailPoint 實例會建立記憶體閘道。 記憶體閘道會先檢查足夠的資源,再起始需要大量記憶體的活動。 檢查失敗會導致 InsufficientMemoryException 擲回例外狀況。 此例外狀況可防止啟動作業,並降低因資源不足而失敗的可能性。 這可讓您降低效能,以避免 OutOfMemoryException 發生例外狀況,以及程式碼中任意位置中例外狀況的不當處理所造成的任何狀態損毀。

重要

此型別代表 IDisposable 介面。 當您完成使用型別時,您應該直接或間接處置它。 若要直接處置型別,請呼叫其 try/catch 區塊中的 Dispose 方法。 若要間接處置它,請使用語言建構函式,例如 using (在 C# 中) 或 Using (在 Visual Basic 中)。 如需詳細資訊,請參閱 IDisposable 介面文章中的<使用實作 IDisposable 的物件>一節。

藉由擲回 InsufficientMemoryException 例外狀況,應用程式可以區分作業無法完成的估計值,以及可能損毀應用程式狀態的部分完成作業。 這可讓應用程式減少封閉式擴大原則的頻率,這可能需要卸載目前 AppDomain 或回收進程。

MemoryFailPoint 會檢查所有垃圾收集堆積中是否有足夠的記憶體和連續虛擬位址空間可用,而且可能會增加交換檔案的大小。 MemoryFailPoint 不會保證閘道存留期間記憶體的長期可用性,但呼叫端應該一律使用 Dispose 方法來確保與 相關聯的 MemoryFailPoint 資源釋放。

若要使用記憶體閘道,您必須建立 MemoryFailPoint 物件,並指定預期下一個作業使用的記憶體 (MB) MB 數目。 如果沒有足夠的記憶體可用, InsufficientMemoryException 則會擲回例外狀況。

建構函式的參數必須是正整數。 負值會 ArgumentOutOfRangeException 引發例外狀況。

MemoryFailPoint 以 16 MB 的資料細微性運作。 小於 16 MB 的任何值都會被視為 16 MB,而其他值則會視為下一個最大 16 MB 的倍數。

建構函式

MemoryFailPoint(Int32)

初始化 MemoryFailPoint 類別的新執行個體,並指定順利執行所需的記憶體容量。

方法

Dispose()

釋放 MemoryFailPoint 所使用的所有資源。

Equals(Object)

判斷指定的物件是否等於目前的物件。

(繼承來源 Object)
Finalize()

確認釋出資源,並在記憶體回收行程回收 MemoryFailPoint 物件時執行其他清除作業。

GetHashCode()

做為預設雜湊函式。

(繼承來源 Object)
GetType()

取得目前執行個體的 Type

(繼承來源 Object)
MemberwiseClone()

建立目前 Object 的淺層複製。

(繼承來源 Object)
ToString()

傳回代表目前物件的字串。

(繼承來源 Object)

適用於