共用方式為


OutOfMemoryException 類別

定義

當記憶體不足以繼續執行程式時拋出的例外。

public ref class OutOfMemoryException : Exception
public ref class OutOfMemoryException : SystemException
public class OutOfMemoryException : Exception
public class OutOfMemoryException : SystemException
[System.Serializable]
public class OutOfMemoryException : SystemException
[System.Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public class OutOfMemoryException : SystemException
type OutOfMemoryException = class
    inherit Exception
type OutOfMemoryException = class
    inherit SystemException
[<System.Serializable>]
type OutOfMemoryException = class
    inherit SystemException
[<System.Serializable>]
[<System.Runtime.InteropServices.ComVisible(true)>]
type OutOfMemoryException = class
    inherit SystemException
Public Class OutOfMemoryException
Inherits Exception
Public Class OutOfMemoryException
Inherits SystemException
繼承
OutOfMemoryException
繼承
OutOfMemoryException
衍生
屬性

備註

OutOfMemoryException 使用 HRESULT COR_E_OUTOFMEMORY,其值為 0x8007000E。

如需查看 OutOfMemoryException 實例的初始屬性值列表,請參閱 OutOfMemoryException 的建構子。

備註

繼承 Data 財產的價值總是 null

例外 OutOfMemoryException 有兩個主要原因:

  • 你試圖將一個物件擴展 StringBuilder 到其屬性所定義 StringBuilder.MaxCapacity 的長度之外。

  • 通用語言執行時無法分配足夠的連續記憶體來成功執行操作。 此例外可由任何需要記憶體配置的屬性指派或方法呼叫拋出。 關於例外原因 OutOfMemoryException 的更多資訊,請參閱部落格文章 《記憶體不足不指實體記憶體》。

    此類 OutOfMemoryException 例外代表災難性的失敗。 如果你選擇處理例外,應該包含 catch 一個區塊,呼叫 Environment.FailFast 終止應用程式的方法,並在系統事件日誌中新增條目,如下範例所示。

    using System;
    
    public class Example
    {
       public static void Main()
       {
          try {
             // Outer block to handle any unexpected exceptions.
             try {
                string s = "This";
                s = s.Insert(2, "is ");
    
                // Throw an OutOfMemoryException exception.
                throw new OutOfMemoryException();
             }
             catch (ArgumentException) {
                Console.WriteLine("ArgumentException in String.Insert");
             }
    
             // Execute program logic.
          }
          catch (OutOfMemoryException e) {
             Console.WriteLine("Terminating application unexpectedly...");
             Environment.FailFast(String.Format("Out of Memory: {0}",
                                                e.Message));
          }
       }
    }
    // The example displays the following output:
    //        Terminating application unexpectedly...
    
    open System
    
    try
        // Outer block to handle any unexpected exceptions.
        try
            let s = "This"
            let s = s.Insert(2, "is ")
    
            // Throw an OutOfMemoryException exception.
            raise (OutOfMemoryException())
        with
        | :? ArgumentException ->
            printfn "ArgumentException in String.Insert"
    
        // Execute program logic.
    with :? OutOfMemoryException as e ->
        printfn "Terminating application unexpectedly..."
        Environment.FailFast $"Out of Memory: {e.Message}"
    // The example displays the following output:
    //        Terminating application unexpectedly...
    
    Module Example
       Public Sub Main()
          Try
             ' Outer block to handle any unexpected exceptions.
             Try
                Dim s As String = "This"
                s = s.Insert(2, "is ")
    
                ' Throw an OutOfMemoryException exception.
                Throw New OutOfMemoryException()
             Catch e As ArgumentException
                Console.WriteLine("ArgumentException in String.Insert")
             End Try
             
             ' Execute program logic.
    
          Catch e As OutOfMemoryException
             Console.WriteLine("Terminating application unexpectedly...")
             Environment.FailFast(String.Format("Out of Memory: {0}",
                                                e.Message))
          End Try
       End Sub
    End Module
    ' The example displays the following output:
    '       Terminating application unexpectedly...
    

觸發例外的條件及你可以採取的消除措施包括以下幾點:

你在打電話給方法 StringBuilder.Insert

你試圖將物件的長度 StringBuilder 增加到超出其 StringBuilder.MaxCapacity 屬性所指定的大小。 以下範例說明OutOfMemoryException當嘗試插入會使物件Length屬性超過最大容量的字串時,呼叫方法所拋StringBuilder.Insert(Int32, String, Int32)出的例外。

using System;
using System.Text;

public class Example
{
   public static void Main()
   {
      StringBuilder sb = new StringBuilder(15, 15);
      sb.Append("Substring #1 ");
      try {
         sb.Insert(0, "Substring #2 ", 1);
      }
      catch (OutOfMemoryException e) {
         Console.WriteLine("Out of Memory: {0}", e.Message);
      }
   }
}
// The example displays the following output:
//    Out of Memory: Insufficient memory to continue the execution of the program.
open System
open System.Text

let sb = StringBuilder(15, 15)
sb.Append "Substring #1 "
|> ignore
try
    sb.Insert(0, "Substring #2 ", 1)
    |> ignore
with :? OutOfMemoryException as e ->
    printfn $"Out of Memory: {e.Message}"
// The example displays the following output:
//    Out of Memory: Insufficient memory to continue the execution of the program.
Imports System.Text

Module Example
   Public Sub Main()
      Dim sb As New StringBuilder(15, 15)
      sb.Append("Substring #1 ")
      Try
         sb.Insert(0, "Substring #2 ", 1)
      Catch e As OutOfMemoryException
         Console.WriteLine("Out of Memory: {0}", e.Message)
      End Try
   End Sub
End Module
' The example displays the following output:
'   Out of Memory: Insufficient memory to continue the execution of the program.

你可以以下兩種方式來解決這個錯誤:

你的應用程式是以 32 位元程序運行。

32位元程序在32位元系統上最多可分配2GB的虛擬使用者模式記憶體,在64位元系統上最多可分配4GB的虛擬使用者模式記憶體。 這會使公共語言執行時更難分配足夠的連續記憶體,當需要大量配置時。 相較之下,64 位元程序最多可配置 8TB 虛擬記憶體。 為了解決這個例外,請重新編譯你的應用程式以針對 64 位元平台。 關於在 Visual Studio 中針對特定平台的資訊,請參閱 「如何:配置專案以針對平台」。

你的應用程式正在洩漏未受管理的資源

雖然垃圾回收器能釋放分配給受管理型別的記憶體,但無法管理分配給非管理資源的記憶體,例如作業系統的句柄(包括檔案的句柄、記憶體映射檔案、管線、登錄鍵和等待的句柄)以及由 Windows API 呼叫或記憶體分配函式(如 malloc)直接分配的記憶體區塊。 會消耗未管理資源的類型實作此 IDisposable 介面。

如果你正在使用一種使用未管理資源的類型,使用完後應該記得呼叫它 IDisposable.Dispose 的方法。 (有些類型也會實作 Close 與某個方法功能相同的 Dispose 方法。)欲了解更多資訊,請參閱 「使用實作 IDisposable 物件」主題。

如果你建立了使用非管理資源的型別,務必實作 Dispose 模式,並在必要時提供終結器。 欲了解更多資訊,請參閱 「Implementing a Dispose」Object.Finalize

你正在嘗試在 64 位元程序中建立一個大型陣列

預設情況下,.NET Framework 的通用語言執行環境不允許大小超過 2GB 的單一物件。 要覆寫這個預設值,你可以使用 <gcAllowVeryLargeObjects> 的設定檔設定,啟用總大小超過 2 GB 的陣列。 在 .NET Core 中,預設支援超過 2 GB 的陣列。

你正在處理記憶體中非常龐大的資料集(例如陣列、集合或資料庫資料集)。

當記憶體中的資料結構或資料集變得非常龐大,以致於通用語言執行時無法為它們分配足夠的連續記憶體時, OutOfMemoryException 就會產生例外。

為了避免例外, OutOfMemoryException 你必須修改應用程式,使記憶體中駐留的資料減少,或將資料分割成需要較小記憶體配置的區段。 例如:

  • 如果你是從資料庫取得所有資料,然後在應用程式中過濾以減少伺服器的流量,你應該修改查詢,只回傳應用程式需要的子集資料。 處理大型資料表時,多次查詢幾乎總是比在單一資料表中取得所有資料再操作更有效率。

  • 如果你執行的是使用者動態建立的查詢,應該確保查詢回傳的記錄數量是有限的。

  • 如果你使用大型陣列或其他集合物件,這些物件大小會導致 OutOfMemoryException 例外,你應該修改應用程式,讓資料分成子集處理,而不是一次處理全部資料。

以下範例取得一個包含2億個浮點數值的陣列,然後計算其平均值。 範例的輸出顯示,因為範例在計算平均值前會先將整個陣列存入記憶體,因此拋出了 a OutOfMemoryException

using System;
using System.Collections.Generic;

public class Example
{
   public static void Main()
   {
      Double[] values = GetData();
      // Compute mean.
      Console.WriteLine("Sample mean: {0}, N = {1}",
                        GetMean(values), values.Length);
   }

   private static Double[] GetData()
   {
      Random rnd = new Random();
      List<Double> values = new List<Double>();
      for (int ctr = 1; ctr <= 200000000; ctr++) {
         values.Add(rnd.NextDouble());
         if (ctr % 10000000 == 0)
            Console.WriteLine("Retrieved {0:N0} items of data.",
                              ctr);
      }
      return values.ToArray();
   }

   private static Double GetMean(Double[] values)
   {
      Double sum = 0;
      foreach (var value in values)
         sum += value;

      return sum / values.Length;
   }
}
// The example displays output like the following:
//    Retrieved 10,000,000 items of data.
//    Retrieved 20,000,000 items of data.
//    Retrieved 30,000,000 items of data.
//    Retrieved 40,000,000 items of data.
//    Retrieved 50,000,000 items of data.
//    Retrieved 60,000,000 items of data.
//    Retrieved 70,000,000 items of data.
//    Retrieved 80,000,000 items of data.
//    Retrieved 90,000,000 items of data.
//    Retrieved 100,000,000 items of data.
//    Retrieved 110,000,000 items of data.
//    Retrieved 120,000,000 items of data.
//    Retrieved 130,000,000 items of data.
//
//    Unhandled Exception: OutOfMemoryException.
open System

let getData () =
    let rnd = Random()
    [|  for i = 1 to 200000000 do
            rnd.NextDouble()
            if i % 10000000 = 0 then
                printfn $"Retrieved {i:N0} items of data." |]
    
let getMean values =
    let sum = Array.sum values

    sum / float values.Length

let values = getData ()
// Compute mean.
printfn $"Sample mean: {getMean values}, N = {values.Length}"

// The example displays output like the following:
//    Retrieved 10,000,000 items of data.
//    Retrieved 20,000,000 items of data.
//    Retrieved 30,000,000 items of data.
//    Retrieved 40,000,000 items of data.
//    Retrieved 50,000,000 items of data.
//    Retrieved 60,000,000 items of data.
//    Retrieved 70,000,000 items of data.
//    Retrieved 80,000,000 items of data.
//    Retrieved 90,000,000 items of data.
//    Retrieved 100,000,000 items of data.
//    Retrieved 110,000,000 items of data.
//    Retrieved 120,000,000 items of data.
//    Retrieved 130,000,000 items of data.
//
//    Unhandled Exception: OutOfMemoryException.
Imports System.Collections.Generic

Module Example
   Public Sub Main()
      Dim values() As Double = GetData()
      ' Compute mean.
      Console.WriteLine("Sample mean: {0}, N = {1}",
                        GetMean(values), values.Length)
   End Sub
   
   Private Function GetData() As Double()
      Dim rnd As New Random()
      Dim values As New List(Of Double)()
      For ctr As Integer = 1 To 200000000
         values.Add(rnd.NextDouble)
         If ctr Mod 10000000 = 0 Then
            Console.WriteLine("Retrieved {0:N0} items of data.",
                              ctr)
         End If
      Next
      Return values.ToArray()
   End Function
   
   Private Function GetMean(values() As Double) As Double
      Dim sum As Double = 0
      For Each value In values
         sum += value
      Next
      Return sum / values.Length
   End Function
End Module
' The example displays output like the following:
'    Retrieved 10,000,000 items of data.
'    Retrieved 20,000,000 items of data.
'    Retrieved 30,000,000 items of data.
'    Retrieved 40,000,000 items of data.
'    Retrieved 50,000,000 items of data.
'    Retrieved 60,000,000 items of data.
'    Retrieved 70,000,000 items of data.
'    Retrieved 80,000,000 items of data.
'    Retrieved 90,000,000 items of data.
'    Retrieved 100,000,000 items of data.
'    Retrieved 110,000,000 items of data.
'    Retrieved 120,000,000 items of data.
'    Retrieved 130,000,000 items of data.
'
'    Unhandled Exception: OutOfMemoryException.

以下範例透過 OutOfMemoryException 處理接收資料而不將整個資料集存入記憶體,必要時將資料序列化成檔案以允許進一步處理(這些行在範例中註解,因為產生的檔案大小大於 1GB),並將計算的平均值與案例數回傳給呼叫例程。

using System;
using System.IO;

public class Example
{
   public static void Main()
   {
      Tuple<Double, long> result = GetResult();
      Console.WriteLine("Sample mean: {0}, N = {1:N0}",
                        result.Item1, result.Item2);
   }

   private static Tuple<Double, long> GetResult()
   {
      int chunkSize = 50000000;
      int nToGet = 200000000;
      Random rnd = new Random();
      // FileStream fs = new FileStream(@".\data.bin", FileMode.Create);
      // BinaryWriter bin = new BinaryWriter(fs);
      // bin.Write((int)0);
      int n = 0;
      Double sum = 0;
      for (int outer = 0;
           outer <= ((int) Math.Ceiling(nToGet * 1.0 / chunkSize) - 1);
           outer++) {
         for (int inner = 0;
              inner <= Math.Min(nToGet - n - 1, chunkSize - 1);
              inner++) {
            Double value = rnd.NextDouble();
            sum += value;
            n++;
            // bin.Write(value);
         }
      }
      // bin.Seek(0, SeekOrigin.Begin);
      // bin.Write(n);
      // bin.Close();
      return new Tuple<Double, long>(sum/n, n);
   }
}
// The example displays output like the following:
//    Sample mean: 0.500022771458399, N = 200,000,000
open System
// open System.IO

let getResult () =
    let chunkSize = 50000000
    let nToGet = 200000000
    let rnd = Random()
    // use fs = new FileStream(@".\data.bin", FileMode.Create)
    // use bin = new BinaryWriter(fs)
    // bin.Write 0
    let mutable n = 0
    let mutable sum = 0.
    for _ = 0 to int (ceil (nToGet / chunkSize |> float) - 1.) do
        for _ = 0 to min (nToGet - n - 1) (chunkSize - 1) do
            let value = rnd.NextDouble()
            sum <- sum + value
            n <- n + 1
            // bin.Write(value)
    // bin.Seek(0, SeekOrigin.Begin) |> ignore
    // bin.Write n
    sum / float n, n

let mean, n = getResult ()
printfn $"Sample mean: {mean}, N = {n:N0}"

// The example displays output like the following:
//    Sample mean: 0.500022771458399, N = 200,000,000
Imports System.IO

Module Example
   Public Sub Main()
      Dim result As Tuple(Of Double, Long) = GetResult()
      Console.WriteLine("Sample mean: {0}, N = {1:N0}",
                        result.Item1, result.Item2)
   End Sub

   Private Function GetResult As Tuple(Of Double, Long)
      Dim chunkSize As Integer = 50000000
      Dim nToGet As Integer = 200000000
      Dim rnd As New Random()
'       Dim fs As New FileStream(".\data.bin", FileMode.Create)
'       Dim bin As New BinaryWriter(fs)
'       bin.Write(CInt(0))
      Dim n As Integer
      Dim sum As Double
      For outer As Integer = 0 To CInt(Math.Ceiling(nToGet/chunkSize) - 1)
         For inner = 0 To Math.Min(nToGet - n - 1, chunkSize - 1)
            Dim value As Double = rnd.NextDouble()
            sum += value
            n += 1
'            bin.Write(value)
         Next
      Next
'       bin.Seek(0, SeekOrigin.Begin)
'       bin.Write(n)
'       bin.Close()
      Return New Tuple(Of Double, Long)(sum/n, n)
   End Function
End Module
' The example displays output like the following:
'   Sample mean: 0.500022771458399, N = 200,000,000

你是在反覆串接大字串。

由於字串是不可變的,每次串接操作都會產生一個新的字串。 對於小字串或少量串接操作的影響可以忽略不計。 但對於大型串列或大量串接操作,串接可能導致大量記憶體配置與碎片化、效能不佳,甚至可能出現 OutOfMemoryException 例外。

當串接大型字串或執行大量串接操作時,應該使用 class 而 StringBuilderString class。 當你操作完字串後,透過呼叫StringBuilder.ToString方法將實例轉換StringBuilder成字串。

你會在記憶體中釘選大量物件。

長時間將大量物件釘在記憶體中,會讓垃圾回收器難以分配連續的記憶體區塊。 如果你在記憶體中釘選了大量物件,例如使用 fixed C# 中的陳述式,或用 的代柄類型GCHandleType.Pinned呼叫GCHandle.Alloc(Object, GCHandleType)方法,你可以用以下方法來處理OutOfMemoryException異常。

  • 評估每個物件是否真的需要釘頂,

  • 確保每個物件盡快解除釘選。

  • 確保每次呼叫 GCHandle.Alloc(Object, GCHandleType) 針腳記憶體的方法,都會有對應的呼叫 GCHandle.Free 來解除針腳該記憶體的方法。

以下 Microsoft 中介(MSIL)指令會拋出 OutOfMemoryException 例外:

建構函式

名稱 Description
OutOfMemoryException()

初始化 OutOfMemoryException 類別的新執行個體。

OutOfMemoryException(SerializationInfo, StreamingContext)
已淘汰.

使用串行化數據,初始化 OutOfMemoryException 類別的新實例。

OutOfMemoryException(String, Exception)

初始化類別的新實例 OutOfMemoryException ,並附上指定的錯誤訊息及導致該異常的內部例外的參考。

OutOfMemoryException(String)

初始化類別的新實例 OutOfMemoryException 並指定錯誤訊息。

屬性

名稱 Description
Data

取得一組鍵值對,提供關於例外的額外使用者定義資訊。

(繼承來源 Exception)
HelpLink

取得或設定與此例外相關的說明檔案連結。

(繼承來源 Exception)
HResult

取得或設定 HRESULT,一個編碼的數值,指派給特定例外。

(繼承來源 Exception)
InnerException

會取得 Exception 造成目前例外的實例。

(繼承來源 Exception)
Message

會收到描述目前例外的訊息。

(繼承來源 Exception)
Source

取得或設定造成錯誤之應用程式或物件的名稱。

(繼承來源 Exception)
StackTrace

會取得呼叫堆疊上即時框架的字串表示。

(繼承來源 Exception)
TargetSite

會取得拋出當前例外的方法。

(繼承來源 Exception)

方法

名稱 Description
Equals(Object)

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

(繼承來源 Object)
GetBaseException()

當在派生類別中被覆寫時,回傳 Exception 是一個或多個後續例外的根因。

(繼承來源 Exception)
GetHashCode()

做為預設哈希函式。

(繼承來源 Object)
GetObjectData(SerializationInfo, StreamingContext)
已淘汰.

在衍生類別中覆寫時,使用例外狀況的相關信息來設定 SerializationInfo

(繼承來源 Exception)
GetType()

取得目前實例的執行時型態。

(繼承來源 Exception)
MemberwiseClone()

建立目前 Object的淺層複本。

(繼承來源 Object)
ToString()

建立並回傳當前例外的字串表示。

(繼承來源 Exception)

事件

名稱 Description
SerializeObjectState
已淘汰.

當例外被序列化以建立包含該例外序列化資料的例外狀態物件時,會發生這種情況。

(繼承來源 Exception)

適用於

另請參閱