java.lang.OutOfMemoryError 잡기?


101

대한 문서java.lang.Error :

오류는 합리적인 응용 프로그램이 포착하려고 시도해서는 안되는 심각한 문제를 나타내는 Throwable의 하위 클래스입니다.

그러나 java.lang.Error의 하위 클래스와 마찬가지로 java.lang.Throwable이러한 유형의 Throwable을 잡을 수 있습니다.

이런 종류의 예외를 잡는 것이 좋은 생각이 아닌 이유를 이해합니다. 내가 아는 한, 우리가 그것을 잡기로 결정하면 catch 핸들러는 자체적으로 메모리를 할당해서는 안됩니다. 그렇지 않으면 OutOfMemoryError다시 던져 질 것입니다.

그래서 제 질문은 :

  1. 잡는 java.lang.OutOfMemoryError것이 좋은 생각 일 수있는 실제 시나리오가 있습니까?
  2. catch하기로 결정한 경우 java.lang.OutOfMemoryErrorcatch 핸들러가 자체적으로 메모리를 할당하지 않는지 어떻게 확인할 수 있습니까 (도구 또는 모범 사례)?


첫 번째 질문에 대해 사용자에게 문제를 알리기 위해 OutOfMemoryError를 잡을 것이라고 추가하겠습니다. 이전에는 catch (Exception e) 절에서 오류가 포착되지 않았으며 사용자에게 피드백이 표시되지 않았습니다.
Josep Rodríguez López

1
예를 들어 거대한 어레이를 할당하는 특정 경우가 있습니다.이 경우 해당 작업과 관련된 OOM 오류를 포착하고 합리적으로 잘 복구 할 수 있습니다. 그러나 큰 코드 덩어리 주위에 try / catch를 배치하고 깨끗하게 복구하고 계속하는 것은 아마도 나쁜 생각 일 것입니다.
Hot Licks 2014-07-18

답변:


85

나는 여기에있는 대부분의 답변에 동의하고 동의하지 않습니다.

OutOfMemoryError내 경험 (Windows 및 Solaris JVM에서) 을 잡을 수있는 여러 시나리오가 있지만 JVM에 OutOfMemoryError대한 죽음 은 매우 드물게 발생 합니다.

를 잡을 수있는 좋은 이유는 단 한 가지이며 OutOfMemoryError, 이는 정상적으로 종료하고 리소스를 깨끗하게 해제하고 가능한 한 최선의 실패 이유를 기록하는 것입니다 (아직 가능한 경우).

일반적으로 OutOfMemoryError힙의 나머지 자원으로 만족할 수없는 블록 메모리 할당으로 인해 발생합니다.

이 때 Error힙이 실패 할당 이전과 할당 된 객체의 동일한 금액을 포함 지금 런타임 정리 필요할 수 있습니다 더 많은 메모리를 해제하는 객체에 대한 참조를 드롭 할 때입니다 발생합니다. 이 경우 계속할 수도 있지만 JVM이 복구 가능한 상태에 있다는 것을 100 % 확신 할 수는 없으므로 확실히 나쁜 생각입니다.

OutOfMemoryErrorJVM이 catch 블록의 메모리 부족을 의미하지 않는 데모 :

private static final int MEGABYTE = (1024*1024);
public static void runOutOfMemory() {
    MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    for (int i=1; i <= 100; i++) {
        try {
            byte[] bytes = new byte[MEGABYTE*500];
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
            long maxMemory = heapUsage.getMax() / MEGABYTE;
            long usedMemory = heapUsage.getUsed() / MEGABYTE;
            System.out.println(i+ " : Memory Use :" + usedMemory + "M/" + maxMemory + "M");
        }
    }
}

이 코드의 출력 :

1 : Memory Use :0M/247M
..
..
..
98 : Memory Use :0M/247M
99 : Memory Use :0M/247M
100 : Memory Use :0M/247M

중요한 것을 실행하는 경우 일반적 Error으로을 잡아서 syserr에 기록한 다음 선택한 로깅 프레임 워크를 사용하여 기록한 다음 리소스를 해제하고 깨끗한 방식으로 종료합니다. 일어날 수있는 최악의 상황은 무엇입니까? 어쨌든 JVM은 죽어 가고 있고 (또는 이미 죽었다), 잡으면 Error적어도 정리할 기회가있다.

주의 할 점은 정리가 가능한 곳에서만 이러한 유형의 오류를 포착해야한다는 것입니다. 담요하지 마십시오 catch(Throwable t) {}처럼 사방 또는 넌센스.


동의합니다. 새 답변에 대한 실험을 게시하겠습니다.
Mister Smith

4
"JVM이 복구 가능한 상태에 있다는 것을 100 % 확신 할 수는 없습니다.": OutOfMemoryError는 프로그램을 일관성없는 상태에 놓은 지점에서 던져졌을 수 있습니다. 왜냐하면 언제 라도 던져 질 수 있기 때문 입니다. stackoverflow.com/questions/8728866/…
Raedwald

OpenJdk1.7.0_40에서는이 코드를 실행할 때 오류나 예외가 발생하지 않습니다. 심지어 MEGABYTE를 GIGABYTE (1024 * 1024 * 1024)로 변경했습니다. 옵티마이 저가 나머지 코드에서 사용되지 않는 변수 'byte [] bytes'를 제거하기 때문입니까?
RoboAlex 2013 년

"OutOfMemoryError를 잡을 수있는 여러 시나리오가 있습니다."" OutOfMemoryError를 잡을 수있는 좋은 이유는 단 한 가지입니다" . 마음을 정하십시오 !!!
Stephen C

3
OutOfMemory 오류를 포착하려는 실제 시나리오 : 2G 이상의 요소가있는 배열을 할당하려고 할 때 발생합니다. 이 경우 오류 이름은 약간 잘못된 이름이지만 여전히 OOM입니다.
Charles Roth

31

다음과 같이 복구 할 수 있습니다 .

package com.stackoverflow.q2679330;

public class Test {

    public static void main(String... args) {
        int size = Integer.MAX_VALUE;
        int factor = 10;

        while (true) {
            try {
                System.out.println("Trying to allocate " + size + " bytes");
                byte[] bytes = new byte[size];
                System.out.println("Succeed!");
                break;
            } catch (OutOfMemoryError e) {
                System.out.println("OOME .. Trying again with 10x less");
                size /= factor;
            }
        }
    }

}

하지만 말이 되나요? 그 밖의 무엇을 하시겠습니까? 처음에 그렇게 많은 메모리를 할당하는 이유는 무엇입니까? 적은 메모리도 괜찮습니까? 어쨌든 이미 그것을 사용하지 않는 이유는 무엇입니까? 또는 그것이 가능하지 않다면 JVM에 처음부터 더 많은 메모리를 제공하지 않는 이유는 무엇입니까?

질문으로 돌아 가기 :

1 : java.lang.OutOfMemoryError를 잡을 때 실제 단어 시나리오가 있습니까?

아무 것도 떠오르지 않습니다.

2 : 만약 우리가 java.lang.OutOfMemoryError를 잡았다면 어떻게 catch 핸들러가 자체적으로 메모리를 할당하지 않는다는 것을 확신 할 수 있습니까 (어떤 도구 나 최선의 방법)?

OOME의 원인에 따라 다릅니다. try블록 외부에서 선언되고 단계별로 발생하면 기회가 거의 없습니다. 미리 일부 메모리 공간을 예약 있습니다 .

private static byte[] reserve = new byte[1024 * 1024]; // Reserves 1MB.

그런 다음 OOME 중에 0으로 설정하십시오.

} catch (OutOfMemoryException e) {
     reserve = new byte[0];
     // Ha! 1MB free!
}

물론 이것은 전혀 의미가 없습니다.) 응용 프로그램에 필요한만큼 JVM에 충분한 메모리를 제공하십시오. 필요한 경우 프로파일 러를 실행하십시오.


1
공간을 예약하더라도 작업 솔루션에 대한 보장은 없습니다. 이 공간은 다른 스레드에서도
차지할 수

@Wolph : 그런 다음 JVM에 더 많은 메모리를 제공하십시오! O_o 모든 것이 실제로 의미가 없습니다.)
BalusC 2010

2
첫 번째 스 니펫은 오류를 유발 한 객체가 단일 BIG 객체 (배열)이기 때문에 작동합니다. catch 절에 도달하면 메모리가 부족한 JVM에서 수집 한 것입니다. try 블록 외부, 다른 스레드 또는 동일한 catch에서 동일한 개체를 사용하는 경우 JVM은이를 수집하지 않으므로 모든 종류의 새 단일 개체를 만들 수 없습니다. 예를 들어 두 번째 스 니펫은 작동하지 않을 수 있습니다.
미스터 스미스

3
왜 단순히 설정하지 null않습니까?
Pacerier 2011

1
@MisterSmith 귀하의 의견이 의미가 없습니다. 큰 물체가 존재하지 않습니다. 처음에는 할당되지 않았습니다. OOM이 트리거되었으므로 확실히 GC가 필요하지 않습니다.
Marquis of Lorne

15

일반적으로 OOM을 잡아서 복구하는 것은 좋지 않습니다.

  1. OOME은 응용 프로그램이 알지도 못하는 스레드를 포함하여 다른 스레드에서도 발생할 수 있습니다. 이러한 스레드는 이제 죽고 알림을 기다리고 있던 모든 스레드가 영원히 멈출 수 있습니다. 간단히 말해, 앱이 종료 될 수 있습니다.

  2. 성공적으로 복구하더라도 JVM은 여전히 ​​힙 부족에 시달릴 수 있으며 결과적으로 애플리케이션은 비정상적으로 수행됩니다.

OOME을 사용하는 가장 좋은 방법은 JVM이 죽도록하는 것입니다.

(이는 JVM 죽는다고 가정합니다 . 예를 들어 Tomcat 서블릿 스레드의 OOM은 JVM을 죽이지 않으며, 이로 인해 Tomcat이 요청에 응답하지 않는 긴장 상태가됩니다. 재시작.)

편집하다

나는 OOM을 전혀 잡는 것이 나쁜 생각이라고 말하는 것이 아닙니다. 문제는 의도적으로 또는 감독을 통해 OOME에서 복구를 시도 할 때 발생합니다. OOM (직접 또는 Error 또는 Throwable의 하위 유형으로)을 발견 할 때마다 다시 발생 시키거나 애플리케이션 / JVM이 종료되도록 조정해야합니다.

참고 : 이것은 OOM에 대한 최대의 견고성을 위해 응용 프로그램이 Thread.setDefaultUncaughtExceptionHandler () 를 사용 하여 OOME이 발생하는 스레드에 관계없이 OOME 이벤트에서 응용 프로그램이 종료되도록하는 핸들러를 설정 해야 함을 시사합니다 . 나는 이것에 대한 의견에 관심이 있습니다 ...

유일한 다른 시나리오는 OOM이 부수적 손상을 초래하지 않았 음 을 확신 하는 경우입니다. 즉 :

  • 구체적으로 OOME의 원인,
  • 그 당시 애플리케이션이 무엇을하고 있었는지, 그 계산을 그냥 버리는 것이 괜찮습니다.
  • (대략) 동시 OOME이 다른 스레드에서 발생할 수 없습니다.

이러한 사항을 알 수있는 응용 프로그램이 있지만 대부분의 응용 프로그램에서는 OOME 이후의 계속이 안전한지 확인할 수 없습니다. 당신이 그것을 시도 할 때 그것이 경험적으로 "작동"하더라도.

(문제는 "예상 된"OOME의 결과가 안전하고 "예상되지 않은"OOME이 try / catch OOME의 제어 내에서 발생할 수 없음을 증명하기 위해 공식적인 증거가 필요하다는 것입니다.)


그래 나도 너와 같은 생각이야. 일반적으로 그것은 나쁜 생각입니다. 그런데 왜 잡을 가능성이 있습니까? :)
Denis Bazhenov

@dotsid-1) 포착해야하는 경우가 있기 때문이고 2) OOM을 포착하지 못하게하면 자바 런타임의 언어 및 / 또는 기타 부분에 부정적인 영향을 미치기 때문입니다.
Stephen C

1
당신은 "당신이 그것을 잡아야 할 경우가 있기 때문에"라고 말합니다. 그래서 이것은 내 원래 질문의 일부였습니다. OOME을 잡으려는 경우는 무엇입니까 ?
Denis Bazhenov

1
@dotsid-내 편집 된 답변을 참조하십시오. OOM을 잡기 위해 제가 생각할 수있는 유일한 경우는 OOM 발생시 다중 스레드 응용 프로그램을 강제 로 종료하기 위해이 작업을 수행해야하는 경우입니다. 의 모든 하위 유형에 대해이 작업을 수행 할 수 Error있습니다.
Stephen C

1
OOME을 잡는 문제가 아닙니다. 또한 복구해야합니다. 스레드 가 다른 스레드에 통지해야하는데 어떻게 복구 합니까?하지만 OOME이 있습니까? 물론 JVM은 죽지 않을 것입니다. 그러나 스레드가 OOME을 잡아서 다시 시작된 스레드의 알림을 기다리기 때문에 응용 프로그램이 작동을 멈출 수 있습니다.
Stephen C

14

예, 실제 시나리오가 있습니다. 여기 내 것이 있습니다. 노드 당 메모리가 제한된 클러스터에서 매우 많은 항목의 데이터 세트를 처리해야합니다. 주어진 JVM 인스턴스는 여러 항목을 차례로 거치지 만 일부 항목은 클러스터에서 처리 OutOfMemoryError하기에는 너무 큽니다. 어떤 항목이 너무 큰지 파악하고 기록 할 수 있습니다 . 나중에 RAM이 더 많은 컴퓨터에서 큰 항목 만 다시 실행할 수 있습니다.

(실패한 어레이의 단일 멀티 기가 바이트 할당이기 때문에 JVM은 오류를 포착 한 후에도 여전히 문제가 없으며 다른 항목을 처리 할 충분한 메모리가 있습니다.)


그래서 당신은 같은 코드가 byte[] bytes = new byte[length]있습니까? 왜 size이전 시점에서 확인하지 않습니까?
Raedwald

1
size더 많은 메모리로도 똑같이 괜찮을 것이기 때문입니다. 대부분의 경우 모든 것이 잘 될 것이기 때문에 예외를 통과합니다.
Michael Kuhn

10

OOME을 잡는 것이 합당한 시나리오가 있습니다. IDEA는이를 포착하고 시작 메모리 설정을 변경할 수있는 대화 상자를 표시합니다 (완료하면 종료 됨). 애플리케이션 서버가이를 포착하고보고 할 수 있습니다. 이를 수행하는 핵심은 디스패치의 높은 수준에서 수행하여 예외를 포착하는 지점에서 많은 리소스를 확보 할 수있는 합리적인 기회를 확보하는 것입니다.

위의 IDEA 시나리오 외에도 일반적으로 캐칭은 OOM뿐만 아니라 Throwable이어야하며 적어도 스레드가 곧 종료되는 컨텍스트에서 수행되어야합니다.

물론 대부분의 경우 기억이 굶주리고 상황은 회복 할 수 없지만 말이되는 방법이 있습니다.


8

내 경우에는 OutOfMemoryError를 잡는 것이 좋은 생각인지 궁금했기 때문에이 질문을 보았습니다. 나는이 오류를 잡는 또 다른 예를 보여주기 위해 부분적으로 대답하고 있습니다.이 오류가 누군가 (예 : 나)에게 이해가 될 수 있고 부분적으로 제 경우에 좋은 아이디어인지 여부를 확인하기 위해 부분적으로 (저는 uber 주니어 개발자이므로 절대 할 수 없습니다 내가 작성한 코드 한 줄에 대해 너무 확신하십시오).

어쨌든 메모리 크기가 다른 여러 장치에서 실행할 수있는 Android 애플리케이션을 개발 중입니다. 위험한 부분은 파일에서 비트 맵을 디코딩하여 ImageView 인스턴스에 표시하는 것입니다. 디코딩 된 비트 맵의 ​​크기 측면에서 더 강력한 장치를 제한하고 싶지 않으며 매우 낮은 메모리로 본 적이없는 일부 고대 장치에서 앱이 실행되지 않을 수도 있습니다. 따라서 나는 이것을한다 :

BitmapFactory.Options bitmapOptions = new BitmapFactory.Options(); 
bitmapOptions.inSampleSize = 1;
boolean imageSet = false;
while (!imageSet) {
  try {
    image = BitmapFactory.decodeFile(filePath, bitmapOptions);
    imageView.setImageBitmap(image); 
    imageSet = true;
  }
  catch (OutOfMemoryError e) {
    bitmapOptions.inSampleSize *= 2;
  }
}

이런 식으로 사용자 또는 사용자의 요구와 기대에 따라 점점 더 강력한 장치를 제공 할 수 있습니다.


1
또 다른 옵션은 시도하고 실패하는 대신 처리 할 수있는 비트 맵의 ​​크기를 계산하는 것입니다. "예외는 예외적 인 경우에 사용해야합니다"-누군가가 말했다고 생각합니다. 그러나 나는 당신의 해결책이 아마도 가장 좋은 방법은 아니지만 아마도 가장 쉬운 방법이라고 말할 것입니다.
jontejj 2013

코덱에 따라 다릅니다. 10MB의 bmp는 아마도 10MB보다 약간 더 많은 힙을 가져 오는 반면 10MB의 JPEG는 "폭발"할 것이라고 상상해보십시오. 나는 내용의 복잡성에 따라 대규모 달라질 수있는 XML 파싱하려는 내 경우에는 동일
다니엘 알더

5

예, 진짜 질문은 "예외 처리기에서 무엇을 하시겠습니까?"입니다. 거의 모든 유용한 경우 더 많은 메모리를 할당합니다. OutOfMemoryError가 발생할 때 진단 작업을 수행 -XX:OnOutOfMemoryError=<cmd>하려면 HotSpot VM에서 제공 하는 후크를 사용할 수 있습니다 . OutOfMemoryError가 발생하면 명령을 실행하고 Java 힙 외부에서 유용한 작업을 수행 할 수 있습니다. 애초에 애플리케이션의 메모리 부족을 방지하기를 원하므로 그 이유를 파악하는 것이 첫 번째 단계입니다. 그런 다음 MaxPermSize의 힙 크기를 적절하게 늘릴 수 있습니다. 다른 유용한 HotSpot 후크는 다음과 같습니다.

-XX:+PrintCommandLineFlags
-XX:+PrintConcurrentLocks
-XX:+PrintClassHistogram

여기 에서 전체 목록보기


생각보다 더 나쁩니다. 는 OutOfMemeoryError 프로그램의 어느 지점에서나 발생할 수 있기 때문에 ( new문 에서뿐만 아니라) 예외를 포착하면 프로그램이 정의되지 않은 상태가됩니다.
Raedwald 2015

5

OutOfMemoryError 오류에서 복구해야하는 응용 프로그램이 있으며 단일 스레드 프로그램에서는 항상 작동하지만 때로는 다중 스레드 프로그램에서는 작동하지 않습니다. 이 애플리케이션은 생성 된 테스트 시퀀스를 테스트 클래스에서 가능한 최대 깊이까지 실행하는 자동화 된 Java 테스트 도구입니다. 이제 UI는 안정적이어야하지만 테스트 케이스 트리를 늘리는 동안 테스트 엔진의 메모리가 부족할 수 있습니다. 나는 이것을 테스트 엔진에서 다음과 같은 종류의 코드 관용구로 처리합니다.

부울 isOutOfMemory = false; //보고에 사용되는 플래그
{
   SomeType largeVar;
   // largeVar에 점점 더 많이 할당하는 메인 루프
   // OK를 종료하거나 OutOfMemoryError를 발생시킬 수 있습니다.
}
catch (OutOfMemoryError 예) {
   // largeVar는 이제 범위를 벗어 났으므로 쓰레기도 마찬가지입니다.
   System.gc (); // largeVar 데이터 정리
   isOutOfMemory = true; // 사용 가능한 플래그
}
// 복구를보고하는 프로그램 테스트 플래그

이것은 단일 스레드 응용 프로그램에서 매번 작동합니다. 하지만 최근에 테스트 엔진을 UI와 별도의 작업자 스레드에 넣었습니다. 이제 메모리 부족은 두 스레드에서 임의로 발생할 수 있으며이를 잡는 방법이 명확하지 않습니다.

예를 들어, UI의 애니메이션 GIF 프레임이 제어 할 수없는 Swing 클래스에 의해 배후에서 생성 된 독점 스레드에 의해 순환되는 동안 OOME이 발생했습니다. 사전에 필요한 모든 리소스를 할당했다고 생각했지만 애니메이터는 다음 이미지를 가져올 때마다 메모리를 할당하고 있습니다. 사람이 제기 OOMEs 처리하는 방법에 대한 아이디어가 있다면 어떤 스레드를, 내가 듣고 싶어요.


단일 스레드 앱에서 생성시 오류가 발생한 문제가있는 새 개체 중 일부를 더 이상 사용하지 않는 경우 이러한 개체는 catch 절에서 수집 될 수 있습니다. 그러나 JVM이 객체가 나중에 사용될 수 있음을 감지하면 수집 할 수 없으며 앱이 폭발합니다. 이 스레드에서 내 대답을 참조하십시오.
Mister Smith

4

OOME은 캐치 될 수 있지만 일반적으로 JVM이 캐치에 도달했을 때 일부 오브젝트를 가비지 수집 할 수 있는지 여부와 그 시간까지 남은 힙 메모리 수에 따라 쓸모가 없습니다.

예 : 내 JVM에서이 프로그램은 완료 될 때까지 실행됩니다.

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
        }
        System.out.println("Test finished");
    }  
}

그러나 캐치에 한 줄만 추가하면 내가 말하는 내용이 표시됩니다.

import java.util.LinkedList;
import java.util.List;

public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();

        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
            System.out.println("size:" +ll.size());
        }
        System.out.println("Test finished");
    }
}

첫 번째 프로그램은 캐치에 도달하면 JVM이 목록이 더 이상 사용되지 않을 것임을 감지하기 때문에 정상적으로 실행됩니다 (이 감지는 컴파일시 수행되는 최적화 일 수도 있음). 따라서 print 문에 도달하면 힙 메모리가 거의 완전히 해제되었으므로 이제 계속 진행할 수있는 넓은 여유 공간이 있습니다. 이것이 최상의 경우입니다.

그러나 llOOME을 포착 한 후 목록 을 사용 하는 등 코드를 정리 하면 JVM이이를 수집 할 수 없다. 이것은 두 번째 스 니펫에서 발생합니다. 새로운 Long 생성에 의해 트리거 된 OOME이 포착되지만 곧 새로운 Object ( System.out,println줄에 문자열 )를 생성하고 힙이 거의 가득 차서 새 OOME이 발생합니다. 이것은 최악의 시나리오입니다. 우리는 새 객체를 만들려고했지만 실패했고 OOME을 잡았습니다. 예,하지만 이제 새 힙 메모리가 필요한 첫 번째 명령 (예 : 새 객체 생성)은 새 OOME을 던집니다. 그것에 대해 생각해보십시오.이 시점에서 메모리가 거의 남아 있지 않은 상태에서 다른 무엇을 할 수 있습니까?. 아마 그냥 나가는 것 같습니다. 따라서 쓸모가 없습니다.

JVM이 리소스를 수집하지 않는 이유 중 하나는 정말 무섭습니다. 다른 스레드와 공유 된 리소스도이를 사용하는 것입니다. 뇌를 가진 사람은 어떤 종류의 실험적이지 않은 앱에 삽입하면 OOME을 잡는 것이 얼마나 위험한지 알 수 있습니다.

Windows x86 32 비트 JVM (JRE6)을 사용하고 있습니다. 각 Java 앱의 기본 메모리는 64MB입니다.


ll=nullcatch 블록 내부에서 수행하면 어떻게 됩니까?
Naanavanalla

3

내가 OOM 오류를 포착하는 이유를 생각할 수있는 유일한 이유는 더 이상 사용하지 않는 대규모 데이터 구조가 있고 null로 설정하고 일부 메모리를 확보 할 수 있기 때문입니다. 그러나 (1) 그것은 당신이 메모리를 낭비하고 있다는 것을 의미하며, OOME 이후에 절뚝 거리는 것보다 코드를 수정해야합니다. 그리고 (2) 그것을 잡았다하더라도 어떻게 하시겠습니까? OOM은 언제든지 발생할 수 있으며 잠재적으로 모든 것을 절반으로 남겨 둡니다.


3

질문 2의 경우 BalusC가 제안한 솔루션을 이미 봅니다.

  1. java.lang.OutOfMemoryError를 잡을 때 실제 단어 시나리오가 있습니까?

좋은 예를 만난 것 같습니다. awt 응용 프로그램이 메시지를 디스패치 할 때 포착되지 않은 OutOfMemoryError가 stderr에 표시되고 현재 메시지의 처리가 중지됩니다. 그러나 응용 프로그램은 계속 실행됩니다! 사용자는 장면 뒤에서 발생하는 심각한 문제를 인식하지 못한 채 다른 명령을 실행할 수 있습니다. 특히 그가 표준 오류를 준수 할 수 없거나 준수하지 않을 때. 따라서 oom 예외를 포착하고 애플리케이션 재시작을 제공 (또는 적어도 제안)하는 것이 바람직합니다.


3

OutOfMemoryError를 잡는 것이 합리적이고 작동하는 것처럼 보이는 시나리오가 있습니다.

시나리오 : Android 앱에서 가능한 가장 높은 해상도로 여러 비트 맵을 표시하고이를 유창하게 확대 / 축소 할 수 있기를 원합니다.

유창한 확대 / 축소 때문에 비트 맵을 메모리에 저장하고 싶습니다. 그러나 Android에는 기기에 따라 제어하기 어려운 메모리 제한이 있습니다.

이 상황에서는 비트 맵을 읽는 동안 OutOfMemoryError가있을 수 있습니다. 여기에서 내가 그것을 잡은 다음 더 낮은 해상도로 계속하면 도움이됩니다.


0
  1. "좋은"을 정의하는 방법에 따라 다릅니다. 버그가있는 웹 애플리케이션에서이를 수행하고 대부분의 경우 작동 합니다 (고맙게도 지금 OutOfMemory은 관련없는 수정으로 인해 발생하지 않음). 그러나이를 포착하더라도 일부 중요한 코드가 손상되었을 수 있습니다. 여러 스레드가있는 경우 해당 스레드 중 하나에서 메모리 할당이 실패 할 수 있습니다. 따라서 애플리케이션에 따라 여전히 10 ~ 90 %의 가능성이 있습니다.
  2. 내가 이해하는 한, 무거운 스택을 풀면 너무 많은 참조가 무효화되므로 신경 쓰지 않아도되는 많은 메모리가 해제됩니다.

편집 : 나는 당신이 그것을 시도하는 것이 좋습니다. 점진적으로 더 많은 메모리를 할당하는 함수를 재귀 적으로 호출하는 프로그램을 작성하십시오. 캐치 OutOfMemoryError하고 의미있는 그 시점부터 계속 할 수 있는지. 내 경험에 따르면 제 경우에는 WebLogic 서버에서 발생 했으므로 약간의 흑 마법이 관련되었을 수 있습니다.


-1

Throwable 아래에서 무엇이든 캐치 할 수 있습니다. 일반적으로 말하면 RuntimeException을 제외한 Exception의 하위 클래스 만 캐치해야합니다.

OutOfMemoryError를 잡는다면 도대체 무엇을 하시겠습니까? VM의 메모리가 부족합니다. 기본적으로 할 수있는 일은 종료하는 것뿐입니다. 메모리를 차지하기 때문에 메모리가 부족하다는 대화 상자를 열 수도 없습니다. :-)

VM은 실제로 메모리가 부족할 때 OutOfMemoryError를 발생시키고 (실제로 모든 오류는 복구 할 수없는 상황을 나타내야 함) 실제로 처리하기 위해 할 수있는 작업이 없어야합니다.

해야 할 일은 메모리가 부족한 이유를 알아 내고 (NetBeans에있는 것과 같은 프로파일 러 사용) 메모리 누수가 없는지 확인하는 것입니다. 메모리 누수가없는 경우 VM에 할당하는 메모리를 늘리십시오.


7
게시물이 지속되는 오해는 OOM이 JVM의 메모리가 부족하다는 것을 나타냅니다. 대신 실제로 JVM이 지시 된 모든 메모리를 할당 할 수 없음을 나타냅니다. 즉, JVM에 10B의 공간이 있고 100B 객체를 '새로 올림'하면 실패하지만 5B 객체를 되돌려 서 '새로 올릴'수 있습니다.
Tim Bender

1
그리고 내가 5B 만 필요하다면 왜 10B를 요구합니까? 시행 착오를 기반으로 할당을 수행하는 경우 잘못하고 있습니다.
TofuBeer

2
Tim은 OutOfMemory 상황에서도 일부 작업을 수행 할 수 있음을 의미했습니다. 예를 들어, 대화 상자를 여는 데 충분한 메모리가 남아있을 수 있습니다.
Stephen Eilert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.