#java #spring #memory-leaks #websphere
#java #весна #утечки памяти #websphere
Вопрос:
У меня есть код, который я использую из другой команды, и я потратил дни, пытаясь отследить предполагаемую утечку памяти в моем приложении. Я получаю ошибку OutOfMemory после нескольких повторных загрузок. Я использовал несколько инструментов для отслеживания утечки, включая YourKit Java Profiler и IBM Support Assisant Memory Analyzer. Мое приложение — это приложение Spring 3.0.5 J2EE, работающее на WebSphere 6.1 с использованием контроллеров, управляемых аннотациями spring-mvc.
Большая часть проведенных мной исследований указывает на класс, который я нахожу очень подозрительным, мы назовем его MyFactory, и он выглядит следующим образом:
import org.springframework.context.ApplicationContextAware;
public final class MyFactory implements ApplicationContextAware {
//this should be changed to be non static after getInstance is removed
private static ApplicationContext applicationContext;
public MyFactory() {
//empty
}
public static SettingObjectFactory getInstance() {
return (MyFactory) applicationContext.getBean("MyFactory");
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
MyFactory.applicationContext = applicationContext;
}
}
В этом классе есть целая куча другой логики, которую я опустил, которая в основном считывает данные из базы данных и сохраняет их в памяти (рядом с кэшем). Однако этот класс, похоже, привязан к ApplicationContext после повторного развертывания приложения.
Является ли classloader этого класса зависающим на ApplicationContext или препятствует его полной очистке? Я знаю, что нам больше не нужен метод getInstance, и я не вижу необходимости в том, чтобы у этого класса был статический ApplicationContext — мне кажется, Spring должен обеспечить одноэлементность этого класса.
Ответ №1:
Да, хранение статической ссылки на ApplicationContext может привести к утечке памяти во многих настройках. Способ, которым некоторые серверы приложений и JVM взаимодействуют со своей загрузкой классов, означает, что объекты, на которые ссылаются статические поля, могут быть сохранены в пуле памяти PermGen (по крайней мере, в JVM Sun Hotspot). Весенние appcontexts могут быть очень большими графиками объектов, в зависимости от того, как выглядит ваша конфигурация контекста.
Единственное постоянное решение этого, которое я нашел, — это избегать горячего развертывания в производственных средах, что позволяет полностью обойти проблему утилизации permgen. Тем не менее, это все еще раздражает в среде разработки.
Комментарии:
1. Спасибо скаффману за подтверждение моих подозрений. Действительно странная вещь в этой проблеме заключается в том, что у нас есть несколько десятков приложений, которые используют этот код, но приложение, над которым я работаю, похоже, единственное, которое допускает утечку памяти. Приложение с утечкой первым использует Spring 3.0.5 (предыдущие приложения были на 2.5.x). Я не могу придумать никаких других различий, из-за которых эта утечка обнаружилась бы сейчас. Есть идеи??
2. @Ryan: Это сильно зависит от того, что содержит контекст. Например, BeanPostProcessors не получают явного значения null’d в контексте, когда он завершает работу, и полагаются на сборку мусора для запуска. Не во всех контекстах они будут использоваться.