Приложения CDI и зависимые области могут сговориться повлиять на сбор мусора?
Мы начинаем экспериментировать с внедрением наших бэкэнд-сервисов с использованием CDI. Сценарий таков:
EJB с @Startup запускается при развертывании EAR. На него вводится ApplicationScoped bean:
@ApplicationScoped
public class JobPlatform {
private PooledExecutor threadHolder;
@Inject @Any
private Instance<Worker> workerSource;
...
bean также имеет метод Observer, который, когда наблюдается событие, получает рабочий bean из экземпляра employeeSource и помещает его в threadPool, где он в конечном итоге заканчивается.
Все работает красиво. Однако... мы начали видеть проблемы с сборкой мусора. Гистограмма кучи JMAP показывает, что многие из этих рабочих висят вокруг, не мусор собрал.
Мы полагаем, что это связано с комбинацией охвата CDI. Страница API для @Dependant (http://docs.jboss.org/cdi/api/1.0-SP1/javax/enterprise/context/Dependent.html) более четко подчеркивает, что в документах:
- Экземпляр bean с областью применения @Dependent, введенный в поле, конструктор bean или метод инициализации является зависимым объектом экземпляра класса компонента bean или Java EE, в который он был введен.
- Экземпляр bean с областью действия @Dependent, введенный в метод-производитель, является зависимым объектом создаваемого экземпляра метода bean.
- Экземпляр bean с областью видимости @Dependent, полученный прямым вызовом экземпляра, является зависимым объектом экземпляра экземпляра.
Итак, следуя этому:
- Рабочий файл bean привязан к JobPlatform и, следовательно, имеет срок службы ApplicationScoped
- Любой рабочий beans, полученный с помощью этого экземпляра, привязан к нему и, следовательно, имеет срок службы ApplicationScoped
- Поскольку beanstore контекста ApplicationScoped (мои знания терминологии здесь немного туманны) по-прежнему имеет ссылку на рабочего beans, они не уничтожаются/собираются мусора
Кто-нибудь, кто использует CDI, согласен с этим? Испытывали ли вы это отсутствие сбора мусора, и если да, можете ли вы предложить какие-либо обходные пути?
Рабочие не могут быть ApplicationScoped, но платформа должна быть. Если бы мы создали пользовательский WorkerScope (uh ohhh...) и аннотировали каждый рабочий класс с ним, было бы достаточно, чтобы отделить зависимость между рабочим и экземпляром?
Есть также некоторые предложения в Можно ли уничтожить область CDI?, на которую я буду смотреть, но хотел, чтобы какая-то резервная копия выглядела как действительная причина.
Надеюсь, вы сможете помочь, спасибо.
Ответы
Ответ 1
Ваше понимание верное. Это был надзор в спецификации, и что-то, что будет зафиксировано в CDI 1.1. Instance
может иметь утечку памяти так же, как вы описали при использовании в долгосрочной перспективе, например SessionScoped
или ApplicationScoped
. То, что вам нужно сделать, - это захватить Contextual
или Bean
для экземпляра и уничтожить его таким образом.
Для того, что вы делаете, и чтобы избежать утечки памяти, вам лучше использовать методы BeanManager для создания экземпляров (таким образом, вы также будете иметь дескриптор Bean
и можете его уничтожить) Instance
.
Ответ 2
При изучении реализации предложенного Джейсоном решения я нашел еще несколько ресурсов, связанных с проблемой:
Проблема: https://issues.jboss.org/browse/CDI-139 и https://issues.jboss.org/browse/WELD-920
Примеры операций beanManager:
https://issues.jboss.org/browse/CDI-14?focusedCommentId=12601344&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-12601344
или
org.jboss.seam.faces.util.BeanManagerUtils