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 문에 도달하면 힙 메모리가 거의 완전히 해제되었으므로 이제 계속 진행할 수있는 넓은 여유 공간이 있습니다. 이것이 최상의 경우입니다.
그러나 ll
OOME을 포착 한 후 목록 을 사용 하는 등 코드를 정리 하면 JVM이이를 수집 할 수 없다. 이것은 두 번째 스 니펫에서 발생합니다. 새로운 Long 생성에 의해 트리거 된 OOME이 포착되지만 곧 새로운 Object ( System.out,println
줄에 문자열 )를 생성하고 힙이 거의 가득 차서 새 OOME이 발생합니다. 이것은 최악의 시나리오입니다. 우리는 새 객체를 만들려고했지만 실패했고 OOME을 잡았습니다. 예,하지만 이제 새 힙 메모리가 필요한 첫 번째 명령 (예 : 새 객체 생성)은 새 OOME을 던집니다. 그것에 대해 생각해보십시오.이 시점에서 메모리가 거의 남아 있지 않은 상태에서 다른 무엇을 할 수 있습니까?. 아마 그냥 나가는 것 같습니다. 따라서 쓸모가 없습니다.
JVM이 리소스를 수집하지 않는 이유 중 하나는 정말 무섭습니다. 다른 스레드와 공유 된 리소스도이를 사용하는 것입니다. 뇌를 가진 사람은 어떤 종류의 실험적이지 않은 앱에 삽입하면 OOME을 잡는 것이 얼마나 위험한지 알 수 있습니다.
Windows x86 32 비트 JVM (JRE6)을 사용하고 있습니다. 각 Java 앱의 기본 메모리는 64MB입니다.