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 屬性所定義的長度。

  • Common Language Runtime 無法配置足夠的連續記憶體,以順利執行作業。 任何需要記憶體配置的屬性指派或方法呼叫都可以擲回這個例外狀況。 如需例外狀況原因 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 的虛擬使用者模式記憶體。 這可讓 Common Language Runtime 在需要大量配置時,配置足夠的連續記憶體更為困難。 相反地,64 位進程最多可配置 8TB 的虛擬記憶體。 若要解決此例外狀況,請重新編譯您的應用程式以 64 位平臺為目標。 如需以Visual Studio中特定平臺為目標的資訊,請參閱如何:將專案設定為目標平臺

您的應用程式正在外泄 Unmanaged 資源

雖然垃圾收集行程能夠釋出配置給 Managed 類型的記憶體,但它不會管理配置給非受控資源的記憶體,例如作業系統控制碼 (包括檔案的控制碼、記憶體對應檔案、管道、登錄機碼,以及等候處理) ,以及直接由Windows API 呼叫所配置的記憶體區塊,或是呼叫記憶體配置函式,例如 malloc 。 使用 Unmanaged 資源的類型會實作 IDisposable 介面。

如果您要使用使用 Unmanaged 資源的型別,當您完成使用它時,請務必呼叫其 IDisposable.Dispose 方法。 (某些類型也會實 Close 作在函式中 Dispose 與 method 相同的方法。) 如需詳細資訊,請參閱 使用實作 IDisposable 的物件 主題。

如果您已建立使用 Unmanaged 資源的類型,請確定您已實作 Dispose 模式,並視需要提供完成項。 如需詳細資訊,請參閱 實作 Dispose 方法和 Object.Finalize

您嘗試在 64 位進程中建立大型陣列

根據預設,.NET Framework中的 Common Language Runtime 不允許大小超過 2GB 的單一物件。 若要覆寫此預設值,您可以使用 <gcAllowVeryLargeObjects> 組態檔設定來啟用總大小超過 2 GB 的陣列。 在 .NET Core 上,預設會啟用大於 2 GB 的陣列支援。

您正在使用非常大型的資料集 (,例如陣列、集合或資料庫資料集,) 記憶體中。

當位於記憶體中的資料結構或資料集變得太大時,Common Language Runtime 無法為其配置足夠的連續記憶體時,就會產生 OutOfMemoryException 例外狀況。

若要避免 OutOfMemoryException 例外狀況,您必須修改應用程式,讓較少的資料駐留在記憶體中,或資料分成需要較小記憶體配置的區段。 例如:

  • 如果您要從資料庫擷取所有資料,然後在您的應用程式中加以篩選,以將伺服器行程降到最低,您應該修改查詢,只傳回應用程式所需的資料子集。 使用大型資料表時,多個查詢幾乎一律比擷取單一資料表中的所有資料更有效率,然後加以操作。

  • 如果您要執行使用者動態建立的查詢,您應該確定查詢所傳回的記錄數目有限。

  • 如果您使用大型陣列或其他產生例外狀況的集合物件 OutOfMemoryException ,您應該修改應用程式,以在子集中處理資料,而不是一次全部使用。

下列範例會取得陣列,其中包含 2 億個浮點值,然後計算其平均值。 此範例的輸出顯示,因為範例會在計算平均值之前,先將整個陣列儲存在記憶體中, 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 狀況。

串連大型字串或執行大量串連作業時,您應該使用 StringBuilder 類別,而不是 String 類別。 當您完成處理字串之後,請呼叫 StringBuilder.ToString 方法,將 StringBuilder 實例轉換成字串。

您會將大量的物件釘選在記憶體中。

在記憶體中釘選大量的物件很長一段時間,可能會讓垃圾收集行程難以配置連續的記憶體區塊。 如果您已在記憶體中釘選大量的物件,例如使用 fixed C# 中的 語句,或呼叫 GCHandle.Alloc(Object, GCHandleType) 具有 控制碼類型的 GCHandleType.Pinned 方法,您可以執行下列動作來解決 OutOfMemoryException 例外狀況。

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

  • 請確定每個物件都儘快取消釘選。

  • 請確定每次呼叫 GCHandle.Alloc(Object, GCHandleType) 方法以釘選記憶體時,都會對 方法進行對應的呼叫, GCHandle.Free 以取消釘選該記憶體。

下列 Microsoft 中繼 (MSIL) 指示會擲回 OutOfMemoryException 例外狀況:

建構函式

OutOfMemoryException()

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

OutOfMemoryException(SerializationInfo, StreamingContext)

使用序列化資料,初始化 OutOfMemoryException 類別的新執行個體。

OutOfMemoryException(String)

使用指定的錯誤訊息,初始化 OutOfMemoryException 類別的新執行個體。

OutOfMemoryException(String, Exception)

使用指定的錯誤訊息以及造成此例外狀況的內部例外狀況的參考,初始化 OutOfMemoryException 類別的新執行個體。

屬性

Data

取得鍵值組的集合,這些鍵值組會提供關於例外狀況的其他使用者定義資訊。

(繼承來源 Exception)
HelpLink

取得或設定與這個例外狀況相關聯的說明檔連結。

(繼承來源 Exception)
HResult

取得或設定 HRESULT,它是指派給特定例外狀況的編碼數值。

(繼承來源 Exception)
InnerException

取得造成目前例外狀況的 Exception 執行個體。

(繼承來源 Exception)
Message

取得描述目前例外狀況的訊息。

(繼承來源 Exception)
Source

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

(繼承來源 Exception)
StackTrace

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

(繼承來源 Exception)
TargetSite

取得擲回目前例外狀況的方法。

(繼承來源 Exception)

方法

Equals(Object)

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

(繼承來源 Object)
GetBaseException()

在衍生類別中覆寫時,傳回一或多個後續的例外狀況的根本原因 Exception

(繼承來源 Exception)
GetHashCode()

做為預設雜湊函式。

(繼承來源 Object)
GetObjectData(SerializationInfo, StreamingContext)

在衍生類別中覆寫時,使用例外狀況的資訊設定 SerializationInfo

(繼承來源 Exception)
GetType()

取得目前執行個體的執行階段類型。

(繼承來源 Exception)
MemberwiseClone()

建立目前 Object 的淺層複製。

(繼承來源 Object)
ToString()

建立並傳回目前例外狀況的字串表示。

(繼承來源 Exception)

事件

SerializeObjectState
已過時。

當例外狀況序列化,以建立包含例外狀況相關序列化資料的例外狀況狀態物件時,就會發生此事件。

(繼承來源 Exception)

適用於

另請參閱