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 当示例尝试插入将导致对象的 属性超出其最大容量的字符串时调用 方法引发 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)

适用于

另请参阅