2012-12-12 2 views
19

try/catch 블록을 사용하여 OutOfMemoryException을 잡을 수 있다는 사실을 조금 혼란스럽게 생각합니다.OutOfMemoryException 잡는 방법은 무엇입니까?

주어진 다음의 코드 :

Console.WriteLine("Starting"); 

for (int i = 0; i < 10; i++) 
{ 
    try 
    { 
     OutOfMemory(); 
    } 
    catch (Exception exception) 
    { 
     Console.WriteLine(exception.ToString()); 
    } 
} 

try 
{ 
    StackOverflow(); 
} 
catch (Exception exception) 
{ 
    Console.WriteLine(exception.ToString()); 
} 

Console.WriteLine("Done"); 

나는에서 OutOfMemory +있는 StackOverflowException을 만드는 데 사용되는 방법 :

public static void OutOfMemory() 
{ 
    List<byte[]> data = new List<byte[]>(1500); 

    while (true) 
    { 
     byte[] buffer = new byte[int.MaxValue/2]; 

     for (int i = 0; i < buffer.Length; i++) 
     { 
      buffer[i] = 255; 
     } 

     data.Add(buffer); 
    } 
} 

static void StackOverflow() 
{ 
    StackOverflow(); 
} 

이 때문에 StackOverflowException,에 OutOfMemoryException 10 배를 출력하고 종료하는 그것은 처리 할 수 ​​없습니다.

램 그래프 모양처럼 그 프로그램을 실행하는 동안 : graph showing that memory gets allocated and released 10 times

내 질문 지금 왜 우리가 OutOfMemoryException을 잡을 수 있습니까? 잡으면 우리가 원하는 코드를 실행할 수 있습니다. RAM 그래프에 의해 입증 된 바와 같이, 메모리가 릴리스되었습니다. 런타임은 어떤 객체를 GC 할 수 있는지, 그리고 계속 실행하려면 어떤 객체를 필요로하는지 어떻게 알 수 있습니까?

+0

OutOfMemory() 메소드를 보여주세요. 내가 할당 한 메모리에 대한 참조를 유지하지 않을 것이므로 GC는 반환 한 후에 GC가이를 해제 할 수 있습니다. –

+0

done, you 're right – GameScripting

+0

그래, OutOfMemory()가 던지 자마자 할당 된 모든 메모리는 GC에 의해 해제 될 수 있습니다. –

답변

24

GC는 프로그램에서 사용되는 참조를 분석하고 아무데도 사용되지 않는 개체를 버릴 수 있습니다.

OutOfMemoryException이 메모리가 완전히 고갈되었다는 의미가 아니라 메모리 할당이 실패했다는 의미입니다. 한 번에 대용량 메모리 영역을 할당하려고 시도하면 여유 메모리가 충분히 남아있을 수 있습니다.

할당을위한 충분한 여유 공간이 없으면 시스템은 가비지 수집을 수행하여 메모리를 확보합니다. 그래도 할당을위한 메모리가 충분하지 않으면 예외가 throw됩니다.

StackOverflowException은 스택이 꽉 찼음을 의미하고 힙이있는 것처럼 제거 할 수 없기 때문에 처리 할 수 ​​없습니다. 예외를 처리 할 코드를 계속 실행하려면 더 많은 스택 공간이 필요하지만 더 이상은 없습니다.

5

OutOfMemoryException은 32 비트 프로그램을 실행 중이므로 메모리 그래프로 시스템의 RAM 양을 표시하지 않으므로 아마도 64 비트로 빌드하고 MemoryFailPoint을 사용하여 이것은 어쨌든 발생합니다.

OutOfMemory() 함수가 무엇인지 알려 주어 더 선명한 그림을 얻을 수도 있습니다.

P. StackOverFlow는 처리 할 수없는 유일한 오류입니다.

편집 : 위에서 언급 한 바와 같이 논리적 인 것으로 생각하여 이전에 언급하지 않았습니다. 예를 들어 '예비'메모리보다 많은 메모리를 할당하려고하면 그렇게 할 수 없습니다. 예외가 발생합니다. data.Add()를 사용하여 큰 배열을 할당 할 때 최종 '불법'추가가 발생하기 전에 오류가 발생하므로 여유 메모리가 남아 있습니다.

그래서 나는이 시점에서 data.Add (버퍼)라고 가정합니다. 이 문제는 400MB 바이트 배열을 '데이터'에 추가하여 2GB 프로세스 제한을 초과 할 때 배열을 빌드하는 동안 발생합니다. 약 10 억 개의 객체를 4 바이트로 배열하면 약 400MB가 될 것으로 예상됩니다.

P. .net 4.5 프로세스 메모리 할당량이 2GB가 될 때까지, 4.5보다 큰 용량을 사용할 수 있습니다.

가비지 컬렉터가 프로그램과 마크 모든 최상위에있는 모든 실행 스레드를 취이 귀하의 질문에 대한 대답하지만, 청소하는 사람 개체가 결정하는 방법에 (간체) 설명이 있는지 여부를

+0

아, 기억력을 잃어서 응용 프로그램 한계를 넘기고 시스템 한계가 아님을 알게됩니다. –

+0

나는 그것을 고치는 법에 관심이 없다. 아무런 문제가 없다. 그것은 CLR이 어떻게 작동하는지에 대한 연구와 이해에 관한 것이 전부이다. – GameScripting

+0

P. StackOverflow 만 잡을 수있는 것은 아닙니다. 'AccessViolationException'도 있습니다. –

0

확실하지 않음 즉 스택 프레임에서 액세스 할 수있는 모든 객체 (즉, 현재 실행중인 지점의 로컬 변수가 가리키는 모든 객체)와 정적 필드가 가리키는 모든 객체를 의미합니다.

그런 다음 이전 수준으로 표시된 개체의 모든 필드가 가리키는 모든 개체를 나타내는 다음 수준 개체를 표시합니다. 이 단계는 새 오브젝트가 표시되지 않을 때까지 반복됩니다.

C#은 일반적인 컨텍스트에서 포인터를 허용하지 않기 때문에 이전 단계가 완료되면 표시되지 않은 개체가 후속 코드에서 액세스 할 수 없으므로 안전하게 정리할 수 있습니다.

메모리 관리자에게 압력을 가하기 위해 할당 한 객체가 참조로 유지되지 않으면 GC가 해당 객체를 정리할 수 있음을 의미합니다. 또한 OutOfMemoryException은 CLR 프로그램의 관리되는 메모리를 가리키는 반면 GC는 해당 "상자"외부에서 약간 작동합니다.

0

OutOfMemoryException을 알아낼 수있는 이유는 언어 디자이너가 당신을 허용하기 때문입니다. 이것이 때로는 (그러나 보통은) 실용적인 이유는 어떤 경우에는 회복 가능한 상황이기 때문입니다.

거대한 배열을 할당하려고하면 OutOfMemoryException이 발생할 수 있지만 그 거대한 배열의 메모리는 실제로 할당되지 않으므로 다른 코드는 여전히 문제없이 실행될 수 있습니다. 또한 예외로 인해 스택 해제가 발생하면 다른 개체가 가비지 수집 대상이되어 사용 가능한 메모리 양이 더 늘어날 수 있습니다.

0

OutOfMemory() 메서드는 메서드 범위에 로컬 인 데이터 구조 (List<byte[]>)를 만듭니다. 실행 스레드가 OutOfMemory 메서드 내부에있는 동안 현재 스택 프레임은 List의 GC 루트로 간주됩니다. 스레드가 catch 블록에서 끝나면 스택 프레임이 팝되고 목록에 실제로 도달 할 수 없게됩니다. 따라서 가비지 컬렉터는 목록을 안전하게 수집 할 수 있다고 결정합니다 (메모리 그래프에서 관찰 한대로 수행).

관련 문제