Подтвердить что ты не робот

Критическая утечка памяти из гуавы - обходной путь

Есть ли способ обхода утечки памяти Google Guava r15 (ссылка на отчет об ошибке) в компоненте кэша?

(Не полагаясь на то, что сервер приложений может очищать вещи и/или считая, что веб-приложение никогда не будет перезапущено/перераспределено)

4b9b3361

Ответ 1

Я думаю, вам не нужно заботиться об этом. В сообщении Tomcat говорится

Темы будут обновляться с течением времени, чтобы избежать вероятной утечки памяти.

IIUIC означает, что после того, как все старые потоки исчезнут, так будут все указатели на старую версию вашего класса.

Подробности: причиной пула потоков является большая стоимость создания потоков. Сам пул взломан, поскольку вы получаете поток, который делал что-то еще, и нить не является апатридом. Создание темы дорого, предполагая, что вам нужно много их и никогда не перерабатывать. Нет ничего плохого в обновлении всех потоков каждые несколько минут, поэтому я надеялся, что временное решение Tomcat прекрасно его решает. Но это не так.

ИЗМЕНИТЬ

Боюсь, я что-то не понял. Связанная ошибка говорит

Кажется, что веб-приложения, использующие кешву, могут столкнуться с утечкой памяти. После нескольких повторных развертываний контейнер приложения сбой или сбой с помощью OutOfMemoryError.

Я думал, что Tomcat может легко его решить, но по какой-то причине это не так. Так что, боюсь, вы сами должны очистить ThreadLocal. Это легко возможно через отражение, соответствующие поля Thread.threadLocals и, возможно, inheritableThreadLocals. Это плохой взлом, и более сложная часть заключается в том, чтобы это произошло, когда ничто не пошло не так, т.е. Когда приложение не загружено.

EDIT 2 и 3

Я думаю, что безопасно делать что-то вроде

Stripped64.threadHashCode = new ThreadHashCode();

поскольку содержащиеся в нем вещи необходимы только для производительности при сильных конфликтах, и они воссоздаются при использовании. Но в соответствии с комментарием MRalwasser, это не поможет вообще, так как живые потоки все равно будут ссылаться на старую ценность. Так что, похоже, нет способа.

Как ThreadLocal работает, сохраняя данные с потоками (а не используя реальный Map<Thread, Something>), вам придется пройти через все потоки и удалять ссылки там. Обманывание частных полей других потоков - ужасная идея, поскольку они не являются потокобезопасными, а также из-за проблем с видимостью.

Другая вещь, которая может или не работает, - это мое предложение на странице . Это всего лишь 20-строчный патч. Или просто подождите, проблема была назначена вчера.

EDIT 4

Местные жители, которые не используются, не могут вызвать никаких проблем. AFAIK единственным использованием этого TL является статистика кеша. Поэтому избегайте загрузки CacheBuilder.recordStats и Cache.stats и Stripped64.

РЕДАКТИРОВАТЬ 5

Похоже, он окончательно закрепится. Из issue:

Дуг исправил это восходящее направление для нас, и мы заправили его обратно в Гуаву: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.9

На первый взгляд его изменение кажется идентичным mine.

EDIT 6

Наконец, это было отмечено как фиксированное, и было объявлено Guava 18.0-rc1. Было просто грустно, что это заняло много времени, учитывая, что изменение совпадает с моим (9 месяцев назад).

Ответ 2

Вы можете использовать ServletListener ClassLoaderLeakPreventor https://github.com/mjiderhamn/classloader-leak-prevention/, который также очищает ThreadLocals от undeploy/stop. Он также имеет исправления/обходные пути для других распространенных утечек.

Ответ 3

Кажется, это недостаток ThreadLocals. Вы получите то же самое каждый раз, когда кладете класс уровня приложения в ThreadLocal.

Единственным обходным решением является перезапуск сервера при развертывании, я думаю. Я думаю, что это известная проблема Java-приложений. Вы уверены, что это единственное место, которое перестает выгружать загрузчик классов?