НАДЕЙ можна наздогнати, але це буде взагалі марно, залежно від того, чи зможе 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 виявляє, що список більше не буде використовуватися (Це виявлення може бути також оптимізацією, зробленою під час компіляції). Таким чином, коли ми дістаємося до заяви про друк, пам'ять купи звільнена майже повністю, тому ми маємо широкий запас маневру для продовження. Це найкращий випадок.
Однак якщо такий код розташований таким чином, як список ll
використовується після того, як OOME був зчеплений, JVM не може його зібрати. Це відбувається у другому фрагменті. OOME, викликаний новим створенням Long, потрапляє, але незабаром ми створюємо новий Об'єкт (String у System.out,println
рядку), і купа майже повна, тому нове OOME кидається. Це найгірший випадок: ми намагалися створити новий об’єкт, нам не вдалося, ми схопили OOME, так, але тепер перша інструкція, яка вимагає нової купи пам’яті (наприклад: створення нового об’єкта), викине новий OOME. Подумайте над тим, що ще ми можемо зробити в цей момент з таким мало пам’яті ?. Напевно, просто виходить. Звідси марне.
Серед причин того, що JVM не збирає ресурси, одна справді страшна: спільний ресурс з іншими потоками також використовує його. Кожен, хто має мозок, може побачити, наскільки небезпечним може бути ловити OOME, якщо його вставити у будь-який неекспериментальний додаток будь-якого типу.
Я використовую 32-бітний JVM (JRE6) для Windows x86. Пам'ять за замовчуванням для кожного додатка Java становить 64 Мб.