Ответ
OutOfMemoryError — это неконтролируемое исключение (java.lang.Error), возникающее, когда виртуальная машина Java (JVM) не может выделить память в куче (heap) для создания нового объекта, и сборщик мусора (Garbage Collector) не может освободить достаточное её количество.
Основные причины:
- Утечки памяти: Объекты остаются достижимыми (например, через статические коллекции), хотя логически уже не нужны.
- Недостаточный размер heap: Параметры
-Xmx(максимальный размер) заданы слишком низко для рабочей нагрузки. - Большие/неограниченные структуры данных: Постоянный рост кэшей или коллекций без очистки.
Пример, вызывающий ошибку:
import java.util.ArrayList;
import java.util.List;
public class OOMExample {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) {
// Бесконечно добавляем массив в 1 МБ
list.add(new byte[1024 * 1024]);
}
}
}
Как диагностировать и предотвратить:
- Настройте размер heap: Укажите адекватные
-Xms(начальный размер) и-Xmxчерез аргументы JVM. - Анализируйте дамп памяти: Используйте
-XX:+HeapDumpOnOutOfMemoryError, а затем анализируйте файл.hprofв Eclipse MAT или VisualVM. - Используйте слабые ссылки: Для кэшей применяйте
WeakHashMapилиSoftReference, чтобы GC мог их очистить. - Профилируйте приложение: Следите за потреблением памяти с помощью Java Flight Recorder (JFR) или JMX.
Ответ 18+ 🔞
Ага, вот эта самая ошибка, которая всех так веселит — OutOfMemoryError. Это, блядь, не просто какое-то исключение, которое можно поймать и тихо проигнорировать. Это, сука, полноценный java.lang.Error, крик души самой JVM, когда она уже не может, блядь, выделить память в куче под новый объект, а сборщик мусора, этот ленивый уёбок, разводит руками и говорит: «Ну я тут нихуя не могу поделать, всё чисто».
Из-за чего обычно случается этот пиздец:
- Утечки памяти, мать их: Объекты, которые уже всем нахуй не сдались, но всё ещё болтаются в памяти, потому что их, например, какая-нибудь статическая коллекция держит за яйца. Мусорщик на них смотрит и такой: «Ну вы же достижимые, блядь, я вас трогать не могу».
- Жмотство с настройками: Куча (
heap) изначально задана размером с напёрсток. Параметры-Xmx(максимальный размер) выставлены так, будто программа будет считать два плюс два, а она, сука, данные целого завода грузит. - Ненасытные структуры: Кэши, которые растут как на дрожжах, или коллекции, в которые пихают всё подряд без ограничений. Пока не накроется всё медным тазом.
Вот, смотри, как это красиво устроить, чтоб у всех глаза на лоб полезли:
import java.util.ArrayList;
import java.util.List;
public class OOMExample {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) {
// А давайте-ка бесконечно пихать в список мегабайтные массивы!
// Что может пойти не так?
list.add(new byte[1024 * 1024]);
}
}
}
Запустишь эту хуйню — и через пару секунд получишь тот самый салют. Ёперный театр.
Что делать, чтобы не оказаться в такой же жопе:
- Не жадничай с памятью: Выставь нормальные
-Xmsи-Xmx. Если приложению нужно 4 гига — дай 4 гига, а не 256 мегабайт, экономька ебаная. - Заставь JVM настучать на саму себя: При запуске добавь волшебный флаг
-XX:+HeapDumpOnOutOfMemoryError. Когда всё рухнет, JVM выплюнет файлик.hprof— дамп памяти в момент агонии. Засунь его потом в Eclipse MAT или VisualVM, и он тебе покажет, кто именно сожрал всю память, этот пидарас шерстяной. - Используй правильные инструменты для кэшей: Не храни всё в обычных
HashMap. Для кэшей естьWeakHashMapилиSoftReference— это такие ссылки, которые сборщик мусора может спокойно выкинуть, если память на исходе. Хитрая жопа, но работает. - Следи за базаром: Профилируй приложение. Включи Java Flight Recorder (JFR) или смотри через JMX, что там творится с памятью в реальном времени. Чтобы не охуеть в последний момент.