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 使用具有值0x8007000E的 HRESULT COR_E_OUTOFMEMORY

有关实例的初始属性值的列表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 了当示例尝试插入导致对象属性超过其最大容量的字符串时调用 StringBuilder.Insert(Int32, String, Int32) 方法引发的 Length 异常。

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 与 method.) 函数 Dispose 相同的方法。有关详细信息,请参阅 “使用实现 IDisposable 的对象 ”主题。

如果已创建使用非托管资源的类型,请确保已实现 Dispose 模式,并在必要时提供终结器。 有关详细信息,请参阅 实现 Dispose 方法和 Object.Finalize

尝试在 64 位进程中创建大型数组

默认情况下,.NET Framework中的公共语言运行时不允许大小超过 2GB 的单个对象。 若要替代此默认值,可以使用 <gcAllowVeryLargeObjects> 配置文件设置启用总大小超过 2 GB 的数组。 在 .NET Core 上,默认启用对大于 2 GB 的数组的支持。

你正在使用非常大的数据集 (,例如数组、集合或数据库数据集,) 内存中。

当驻留在内存中的数据结构或数据集变得如此之大时,公共语言运行时无法为其分配足够的连续内存时,异常 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)

适用于

另请参阅