Приложения 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