다음을 통해 공유


OutOfMemoryException 클래스

정의

메모리가 부족하여 프로그램 실행을 계속할 수 없을 때 throw되는 예외입니다.

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 .

  • 공용 언어 런타임은 작업을 성공적으로 수행하기에 충분한 연속 메모리를 할당할 수 없습니다. 이 예외는 메모리 할당이 필요한 속성 할당 또는 메서드 호출에 의해 throw될 수 있습니다. 예외의 OutOfMemoryException 원인에 대한 자세한 내용은 블로그 게시물 "메모리 부족"이 실제 메모리를 참조하지 않음을 참조하세요.

    이 유형의 OutOfMemoryException 예외는 치명적인 오류를 나타냅니다. 예외를 처리하도록 선택하는 경우 다음 예제와 같이 메서드를 호출 Environment.FailFast 하여 앱을 종료하고 시스템 이벤트 로그에 항목을 추가하는 블록을 포함 catch 해야 합니다.

    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...
    

예외가 throw되는 일부 조건과 예외를 제거하기 위해 수행할 수 있는 작업에는 다음이 포함됩니다.

메서드를 호출하고 StringBuilder.Insert 있습니다.

개체의 StringBuilder 길이를 해당 속성에 지정된 StringBuilder.MaxCapacity 크기 이상으로 늘리려고 합니다. 다음 예제에서는 개체 LengthOutOfMemoryException 속성이 최대 용량을 StringBuilder.Insert(Int32, String, Int32) 초과하는 문자열을 삽입하려고 할 때 메서드를 호출하여 throw되는 예외를 보여 줍니다.

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 호출해야 합니다. (일부 형식은 함수 Dispose 에서 Close 메서드와 동일한 메서드도 구현합니다.) 자세한 내용은 IDisposable을 구현하는 개체 사용 항목을 참조하세요.

관리되지 않는 리소스를 사용하는 형식을 만든 경우 Dispose 패턴을 구현했는지 확인하고 필요한 경우 종료자를 제공했는지 확인합니다. 자세한 내용은 Dispose 메서드 구현Object.Finalize.

64비트 프로세스에서 큰 배열을 만들려고 합니다.

기본적으로 .NET Framework의 공용 언어 런타임은 크기가 2GB를 초과하는 단일 개체를 허용하지 않습니다. 이 기본값을 재정의 <하려면 gcAllowVeryLargeObjects> 구성 파일 설정을 사용하여 총 크기가 2GB를 초과하는 배열을 사용하도록 설정할 수 있습니다. .NET Core에서는 기본적으로 2GB보다 큰 배열에 대한 지원이 사용하도록 설정됩니다.

메모리에서 매우 큰 데이터 집합(예: 배열, 컬렉션 또는 데이터베이스 데이터 집합)을 작업하고 있습니다.

메모리에 상주하는 데이터 구조 또는 데이터 집합이 너무 커서 공용 언어 런타임에서 해당 개체에 대해 충분한 연속 메모리를 할당할 수 없는 경우 예외가 OutOfMemoryException 발생합니다.

예외를 OutOfMemoryException 방지하려면 메모리에 더 적은 데이터가 상주하거나 데이터가 더 작은 메모리 할당이 필요한 세그먼트로 나뉘도록 애플리케이션을 수정해야 합니다. 다음은 그 예입니다.

  • 데이터베이스에서 모든 데이터를 검색한 다음 앱에서 필터링하여 서버로의 여행을 최소화하는 경우 앱에 필요한 데이터의 하위 집합만 반환하도록 쿼리를 수정해야 합니다. 큰 테이블로 작업할 때 여러 쿼리는 단일 테이블의 모든 데이터를 검색한 다음 조작하는 것보다 거의 항상 더 효율적입니다.

  • 사용자가 동적으로 만드는 쿼리를 실행하는 경우 쿼리에서 반환되는 레코드 수가 제한되어 있는지 확인해야 합니다.

  • 큰 배열 또는 크기가 예외로 발생하는 OutOfMemoryException 다른 컬렉션 개체를 사용하는 경우 애플리케이션을 한 번에 모두 사용하는 대신 하위 집합에서 데이터를 작동하도록 수정해야 합니다.

다음 예제에서는 2억 부동 소수점 값으로 구성된 배열을 가져오고 해당 평균을 계산합니다. 예제의 출력은 평균을 계산하기 전에 전체 배열을 메모리에 저장하기 때문에 throw됨을 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.

다음 예제에서는 메모리에 전체 데이터 집합을 저장하지 않고 들어오는 데이터를 처리하고, 필요한 경우 데이터를 파일로 직렬화하여 추가 처리를 허용하고(이 경우 크기가 1GB보다 큰 파일을 생성하기 때문에 이 줄은 예제에서 주석 처리됨) 계산된 평균과 사례 수를 호출 루틴에 반환하여 예외를 제거 OutOfMemoryException 합니다.

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 예외가 발생할 수 있습니다.

큰 문자열을 연결하거나 많은 수의 연결 작업을 수행하는 경우 클래스 대신 클래스를 StringBuilderString 사용해야 합니다. 문자열 조작을 마쳤으면 메서드를 호출하여 인스턴스를 문자열로 변환 StringBuilder 합니다 StringBuilder.ToString .

메모리에 많은 수의 개체를 고정합니다.

오랫동안 메모리에 많은 개체를 고정하면 가비지 수집기에서 연속된 메모리 블록을 할당하기가 어려울 수 있습니다. 예를 들어 C#의 문을 사용 fixed 하거나 핸들 형식의 메서드를 호출 GCHandle.Alloc(Object, GCHandleType) 하여 메모리에 많은 수의 GCHandleType.Pinned개체를 고정한 경우 다음을 수행하여 예외를 OutOfMemoryException 해결할 수 있습니다.

  • 각 개체를 실제로 고정해야 하는지 여부를 평가합니다.

  • 각 개체가 가능한 한 빨리 고정 해제되었는지 확인합니다.

  • 메모리를 고정하는 메서드에 대한 GCHandle.Alloc(Object, GCHandleType) 각 호출에 해당 메모리를 고정 해제하는 GCHandle.Free 메서드에 대한 해당 호출이 있는지 확인합니다.

다음 MSIL(Microsoft Intermediate) 지침은 예외를 OutOfMemoryException throw합니다.

생성자

Name Description
OutOfMemoryException()

OutOfMemoryException 클래스의 새 인스턴스를 초기화합니다.

OutOfMemoryException(SerializationInfo, StreamingContext)
사용되지 않음.

직렬화된 데이터를 사용하여 클래스의 새 인스턴스를 OutOfMemoryException 초기화합니다.

OutOfMemoryException(String, Exception)

지정된 오류 메시지와 이 예외의 OutOfMemoryException 원인인 내부 예외에 대한 참조를 사용하여 클래스의 새 인스턴스를 초기화합니다.

OutOfMemoryException(String)

지정된 오류 메시지를 사용하여 클래스의 OutOfMemoryException 새 인스턴스를 초기화합니다.

속성

Name Description
Data

예외에 대한 추가 사용자 정의 정보를 제공하는 키/값 쌍의 컬렉션을 가져옵니다.

(다음에서 상속됨 Exception)
HelpLink

이 예외와 연결된 도움말 파일에 대한 링크를 가져오거나 설정합니다.

(다음에서 상속됨 Exception)
HResult

특정 예외에 할당된 코딩된 숫자 값인 HRESULT를 가져오거나 설정합니다.

(다음에서 상속됨 Exception)
InnerException

현재 예외를 Exception 발생시킨 인스턴스를 가져옵니다.

(다음에서 상속됨 Exception)
Message

현재 예외를 설명하는 메시지를 가져옵니다.

(다음에서 상속됨 Exception)
Source

오류를 발생시키는 애플리케이션 또는 개체의 이름을 가져오거나 설정합니다.

(다음에서 상속됨 Exception)
StackTrace

호출 스택에서 직접 실행 프레임의 문자열 표현을 가져옵니다.

(다음에서 상속됨 Exception)
TargetSite

현재 예외를 throw하는 메서드를 가져옵니다.

(다음에서 상속됨 Exception)

메서드

Name Description
Equals(Object)

지정된 개체가 현재 개체와 같은지 여부를 확인합니다.

(다음에서 상속됨 Object)
GetBaseException()

파생 클래스에서 재정의되는 경우 하나 이상의 후속 예외의 근본 원인인 값을 반환 Exception 합니다.

(다음에서 상속됨 Exception)
GetHashCode()

기본 해시 함수로 사용됩니다.

(다음에서 상속됨 Object)
GetObjectData(SerializationInfo, StreamingContext)
사용되지 않음.

파생 클래스에서 재정의되는 경우 예외에 SerializationInfo 대한 정보를 사용하여 설정합니다.

(다음에서 상속됨 Exception)
GetType()

현재 인스턴스의 런타임 형식을 가져옵니다.

(다음에서 상속됨 Exception)
MemberwiseClone()

현재 Object단순 복사본을 만듭니다.

(다음에서 상속됨 Object)
ToString()

현재 예외의 문자열 표현을 만들고 반환합니다.

(다음에서 상속됨 Exception)

이벤트

Name Description
SerializeObjectState
사용되지 않음.

예외에 대한 직렬화된 데이터를 포함하는 예외 상태 개체를 만들기 위해 예외가 serialize될 때 발생합니다.

(다음에서 상속됨 Exception)

적용 대상

추가 정보