Почему это мусор? - PullRequest
       13

Почему это мусор?

1 голос
/ 14 июля 2009

У нас с разработчиками возникает проблема с мусором, собираемым в нашем приложении, когда мы этого не хотим. Мы используем Java с Weblogic 10g3. Мы программируем одноэлементный шаблон для обработки всех наших соединений JMS.

Участвуют два класса:

public class JMSObject {
...
private MessageProducer _producer;
private MessageConsumer _consumer;
...
// standard get/set procs... etc.
}

public class JMSFactory {
...
// Hashmap sessions with key == ConnectionFactory Name
    Hashmap<String, List<Session>> _sessions;

// Hashmap of JMSObjects with key == ConnectionFactory Name + JMS Queue Name
    Hashmap<String, List<JMSObject>> _jmsobjects;
...
// standard get/set & necessary sington functions
}

Метод init сервлетов вызывает метод JMSFactory singlton, любые новые сеансы помещаются в хеш-карту _sessions, а новые MessageConsumer / MessageProducers создаются как JMSObject и помещаются в хеш-карту _jmsobjects в соответствующем списке.

Проблема в том, что когда система запускает объекты JMSObject в списке, они собирают мусор через некоторое время (иногда через 5 минут, иногда через несколько часов). Мы смотрели на это в течение нескольких дней, но не смогли найти причину. для объектов JMSO, подлежащих сбору. Поскольку у JMSFactory есть ссылка на них, зачем gc уничтожает их?

В конце мы исправили это, изменив классы следующим образом (без изменения интерфейсов методов):

public class JMSObject {
...
private List<MessageProducer> _producers;
private List<MessageConsumer> _consumers;
...
// standard get/set procs... etc.
}

public class JMSFactory {
...
// Hashmap sessions with key == ConnectionFactory Name
    Hashmap<String, List<Session>> _sessions;

// Hashmap of JMSObjects with key == ConnectionFactory Name + JMS Queue Name
    private Hashmap<String JMSObject> _jmsobjects;
...
// standard get/set & necessary sington functions
}

Пока что при тестировании JMSObjects не получают gc'ed. Работает уже 2 дня.

Может кто-нибудь объяснить, почему косвенная ссылка вызывает получение объекта JMSObject? И почему сеансы в Hessmap _sessions не получают gc'ed? Имеет ли это какое-либо отношение к тому факту, что сеансы построены в типах Javax, а JMSObject - это то, что мы написали?

Ответы [ 5 ]

5 голосов
/ 14 июля 2009

Поскольку у JMSFactory есть ссылка на них, зачем gc уничтожает их?

Хорошо, какие-либо объекты все еще содержат ссылку на JMSFactory на данный момент?

Типичный одноэлементный шаблон сохраняет ссылку на одноэлементный объект в статическом члене:

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {
        //constructor...
    }

    public static Singleton getInstance() { return instance; }
}

Разве это не тот шаблон, которому вы следуете? Невозможно отличить код, который вы указали в своем сообщении, поскольку вы не указали фактический одноэлементный код ...

(Кстати, использование синглетонов для чего-то подобного звучит так, как если бы это было трудно испытать. См. Синглтоны - патологические лжецы )

2 голосов
/ 14 июля 2009

Мне кажется, я знаю, в чем ваша проблема, я столкнулся с этим некоторое время назад (в WebLogic 6). Я полагаю, что это связано с перезагрузкой динамических классов WebLogic, что WebLogic, кажется, делает время от времени, даже когда вы не в среде разработки (я предполагаю, что web.xml каким-то образом затрагивается каким-либо сервисом или чем-то другим ).

В нашем случае произошло то, что, как и у вас, у нас есть один экземпляр объекта, который определен как статическая переменная некоторого класса, и, как и вы, он инициализируется сервлетом, у которого есть параметр загрузки при запуске. задавать. Когда WebLogic считает, что произошли изменения, он перезагружает веб-приложение путем сбора мусора загрузчиком классов (что нормально) , но не переинициализирует все сервлеты, помеченные как «загрузка при запуске» (в в нашем случае, и я полагаю, что ваш сервлет не служит никакой другой цели, кроме как инициализировать статическую переменную, нет сопоставлений с ней, и поэтому он не может быть вызван, статическая переменная получает GCed, но не переинициализируется, и сервер должен быть перезапущен.

В нашем случае нашим решением было инициализировать статическую переменную в статическом инициализаторе. Первоначальный разработчик использовал сервлет для инициализации переменной, потому что он хотел получить некоторую информацию о контексте сервлета, которая действительно не нужна. Если вам нужна контекстная информация, вы можете попробовать выполнить инициализацию в ServletContextListener .

1 голос
/ 14 июля 2009

Не имея всего кода, этот сложный вопрос решить. Но есть инструменты, которые могут помочь.

Попробуйте эту ссылку: http://blog.emptyway.com/2007/04/02/finding-memory-leaks-in-java-apps/ Он предоставляет информацию об использовании jhat и jmap. Хотя статья написана для поиска утечек памяти, она содержит информацию о том, как отслеживать ссылки на объект. Может быть, вы можете отследить, почему ваши ссылки исчезают.

0 голосов
/ 14 июля 2009

Есть ли вероятность того, что загрузчик классов, который загрузил JMSFactory, был выгружен, в результате чего класс JMSFactory стал GC-файлом (включая экземпляр singleton), что освобождает HashMaps и их содержимое?

0 голосов
/ 14 июля 2009

Вы сказали, что сеансы в карте _sessions не были GC'd, но объекты JMSO не были. Я сомневаюсь, что это потому, что это то, что вы написали. Похоже, либо собирается сама JMSFactory (то есть синглтон не реализован должным образом), либо что-то удаляет ключи с карт. В любом случае объекты JMSObject будут иметь право на сборщик мусора, но объекты сеанса - нет, поскольку в списке все еще есть ссылка на них.

...