Может ли объявление статического ApplicationContext вызвать утечку памяти? (Весна 3)

#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 в контексте, когда он завершает работу, и полагаются на сборку мусора для запуска. Не во всех контекстах они будут использоваться.