OOME może zostać przechwycone, ale będzie generalnie bezużyteczne, w zależności od tego, czy JVM jest w stanie zebrać niektóre obiekty po osiągnięciu pułapki i ile pamięci sterty pozostało do tego czasu.
Przykład: w mojej JVM ten program działa do końca:
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");
}
}
Jednak dodanie tylko jednej linii na haczyku pokaże ci, o czym mówię:
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");
}
}
Pierwszy program działa dobrze, ponieważ po osiągnięciu złapania JVM wykrywa, że lista nie będzie już używana (to wykrycie może być również optymalizacją wykonaną w czasie kompilacji). Więc kiedy dochodzimy do instrukcji print, pamięć sterty została prawie całkowicie zwolniona, więc mamy teraz szeroki margines manewru, aby kontynuować. To jest najlepszy przypadek.
Jeśli jednak kod jest ułożony tak, jak lista ll
jest używana po przechwyceniu OOME, JVM nie może go zebrać. Dzieje się to w drugim fragmencie. OOME, wyzwalane przez nową kreację Long, zostaje przechwycone, ale wkrótce tworzymy nowy obiekt (ciąg w System.out,println
linii), a sterta jest prawie pełna, więc wyrzucany jest nowy OOME. To jest najgorszy scenariusz: próbowaliśmy stworzyć nowy obiekt, nie udało nam się, złapaliśmy OOME, tak, ale teraz pierwsza instrukcja wymagająca nowej pamięci sterty (np .: utworzenie nowego obiektu) wyrzuci nowy OOME. Pomyśl o tym, co jeszcze możemy zrobić w tym momencie z tak małą ilością pamięci? Prawdopodobnie właśnie wychodzę. Stąd bezużyteczne.
Wśród powodów, dla których JVM nie gromadzi zasobów, jeden jest naprawdę przerażający: współdzielony zasób z innymi wątkami również go używającymi. Każdy, kto ma mózg, może zobaczyć, jak niebezpieczne może być złapanie OOME, jeśli zostanie włożone do jakiejś nieeksperymentalnej aplikacji.
Używam 32-bitowej maszyny JVM systemu Windows x86 (JRE6). Domyślna pamięć dla każdej aplikacji Java to 64 MB.