OutOfMemoryException 類別
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
當記憶體不足以繼續執行程式時拋出的例外。
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 使用 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.
你可以以下兩種方式來解決這個錯誤:
將對 StringBuilder.StringBuilder(Int32, Int32) 建構子的呼叫替換為呼叫任何其他 StringBuilder 建構器超載。 你的 StringBuilder 物件最大容量會設定為預設值,也就是 Int32.MaxValue。
呼叫 StringBuilder.StringBuilder(Int32, Int32) 建構子,設定
maxCapacity一個足夠大的值以容納物件的任何 StringBuilder 擴展。
你的應用程式是以 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 而 StringBuilder 非 String 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) |