Ответ
Нет, deadlock сам по себе не вызывает утечку памяти (memory leak), но приводит к зависанию программы (liveness failure).
Почему нет утечки? Утечка памяти — это ситуация, когда объекты больше не нужны, но остаются достижимыми для GC, занимая память. В deadlock'е потоки заблокированы навсегда, но ссылки на объекты (в том числе на объекты-мониторы) остаются активными и легитимными — они находятся в стеках заблокированных потоков. Эти объекты по-прежнему достижимы, поэтому GC их не соберет, но это не считается утечкой, так как они являются частью рабочего состояния приложения (хоть и некорректного).
Пример классического deadlock:
final Object lock1 = new Object();
final Object lock2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock1) { // t1 захватывает lock1
Thread.sleep(100);
synchronized (lock2) { } // t1 ждет lock2, который у t2
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) { // t2 захватывает lock2
Thread.sleep(100);
synchronized (lock1) { } // t2 ждет lock1, который у t1
}
});
t1.start();
t2.start();
// Оба потока заблокированы навсегда.
Основные проблемы deadlock:
- Отказ в обслуживании: Потоки не могут прогрессировать.
- Блокировка ресурсов: Захваченные ресурсы (соединения, файлы) не освобождаются.
Способы предотвращения:
- Упорядочивание блокировок: Всегда захватывайте несколько блокировок в одном и том же глобальном порядке.
- Использование
tryLockс таймаутом из пакетаjava.util.concurrent.locks. - Статический анализ кода для выявления потенциальных deadlock'ов.
Ответ 18+ 🔞
А, слушай, вот эта тема про deadlock и утечки памяти — это вообще отдельная песня, блядь. Люди часто путают, думают, что если всё зависло, то память тут же потечёт, как из дырявого ведра. Ан нет, ёпта!
Так вот, deadlock — это не про утечку, это про то, что твоя программа превращается в красивый, но абсолютно мёртвый памятник самой себе. Утечка памяти — это когда объекты уже нахуй не нужны, но они, как назойливые мухи, болтаются в памяти, и сборщик мусора на них смотрит и рыдает, потому что они формально ещё «достижимы». А в deadlock'е всё иначе, блядь.
Почему утечки нет, объясняю на пальцах: Когда потоки повисли в мертвой хватке, они нихуя не делают, но они живые, сука! Они сидят в своих стеках и крепко держат в лапках ссылки на объекты-замки (lock1, lock2). Для сборщика мусора эти объекты — святые коровы, они нужны потокам (по крайней мере, потоки так думают). Поэтому GC пройдёт мимо, махнёт рукой: «Живите, блядь, сколько хотите». Память не освобождается, но и не течёт — она просто заморожена, как суп в холодильнике. Это не утечка, это отказ в обслуживании, ёперный театр!
Вот, смотри, классика жанра, как сами себе ногу прострелить:
final Object lock1 = new Object();
final Object lock2 = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock1) { // t1 схватил lock1
Thread.sleep(100);
synchronized (lock2) { } // t1 ждёт lock2, а он у t2, пиздец
}
});
Thread t2 = new Thread(() -> {
synchronized (lock2) { // t2 схватил lock2
Thread.sleep(100);
synchronized (lock1) { } // t2 ждёт lock1, а он у t1, вот и повесились оба
}
});
t1.start();
t2.start();
// Всё, приехали. Сидят два потока и смотрят друг на друга, как дураки.
Чем это всё пахнет, кроме жареного?
- Полный швах: Ни один поток никуда не двинется, программа — труп.
- Ресурсы в заложниках: Всё, что они захватили (соединения к базе, файлы), повисло намертво. Другие потоки тоже могут встать в очередь и подохнуть с голоду.
Как не наступить на эти грабли, а?
- Порядок, блядь, порядок! Всегда хватай несколько замков в одном и том же порядке. Если все сначала берут
lock1, а потомlock2, то deadlock'у просто неоткуда взяться, он обосрётся на подходе. - Не жди вечно, идиот! Используй
tryLockс таймаутом изjava.util.concurrent.locks. Не получилось взять замок за отведённое время — отступи, подумай, выпей чаю, попробуй снова. Не упорствуй, как Герасим с Муму. - Дай почитать код умным инструментам. Пусть статические анализаторы поковыряются в твоём творении, они такие паттерны чуют за версту.
Короче, deadlock — это про логику, про живность программы, а не про мусор в памяти. Запомни это, а то будешь искать утечку там, где её нет, и охуеешь от безысходности.