Почему истек @ViewScoped beans не уничтожается до истечения срока действия сеанса

Я использую Mojarra 2.2.4 на GlassFish 4 с Java 7.

Как я понимаю из ответа BalusC на Как и когда @ViewScoped bean уничтожен в JSF?, @ViewScoped beans должен быть уничтожен в трех случаях

  • Постобработка с нулевым результатом
  • Срок действия сеанса
  • Максимальное количество логических просмотров в сеансе превышено

Мой beans уничтожается в первых двух случаях, но не тогда, когда превышено максимальное количество логических просмотров. Я проверил, что beans истекает при превышении максимального значения (я получаю исключение ViewExpiredException), но они все еще не уничтожаются до истечения срока действия сеанса.

По соображениям потребления памяти я хотел бы, чтобы в этом третьем случае был уничтожен beans, тем более что они не могут использоваться после истечения срока действия.

Вопросы

  • Почему beans не уничтожается, когда они истекают?
  • Является ли это ошибкой или ожидаемым поведением?
  • Что было бы чистой работой, чтобы убедиться, что beans будет уничтожен?

Минимальный пример

Вот мой bean:

@javax.inject.Named("sandboxController")
@javax.faces.view.ViewScoped
public class SandboxController implements Serializable {
    private static final Logger log = Logger.getLogger(SandboxController.class.getName());
    @PostConstruct
    public void postConstruct() {
        log.log(Level.INFO, "Constructing SandboxController");
    }
    @PreDestroy
    public void preDestroy() {
        log.log(Level.INFO, "Destroying SandboxController");
    }
    public String getData() {
        return "abcdefg";
    }
}

и мой sandbox.xhtml:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <body>
        <h:form>
            <h:outputText value="#{sandboxController.data}"/>
        </h:form>
    </body>
</html>

и часть моего web.xml:

<context-param>  
    <param-name>com.sun.faces.numberOfLogicalViews</param-name>
    <param-value>3</param-value>
</context-param>
<context-param>  
    <param-name>com.sun.faces.numberOfViewsInSession</param-name>  
    <param-value>3</param-value>
</context-param>

Если я обновляю sandbox.xhtml 50 раз, я получаю 50 копий INFO: Constructing SandboxController в журнале. beans не уничтожаются, независимо от того, сколько раз я обновляю. VisualVM подтверждает, что beans по-прежнему ссылается на UIViewRoot ViewMap. В моем полноразмерном bean, который поддерживает справедливое состояние, я быстро получаю исключение OutOfMemoryException.

Когда я заканчиваю сеанс вручную, я получаю 50 копий INFO: Destroying SandboxController.

Если я добавлю кнопку отправки в файл sandbox.xhtml и загрузим ее в 4 разных вкладки, попробуйте отправить первый, я получаю ViewExpiredException, как и ожидалось, но bean все еще не уничтожен.

Поведение такое же, если я вместо этого использую аннотации javax.faces.bean.ManagedBean и javax.faces.view.ViewScoped. Тем не менее, аннотация OmniFaces org.omnifaces.cdi.ViewScoped работает правильно.

Чтобы уточнить...

My @ViewScoped beans уничтожаются при истечении срока действия сеанса, в отличие от проблем, описанных в связанных вопросах, таких как Связанные ViewScoped beans приводят к утечкам памяти

Я не спрашиваю, почему каждый bean не сразу уничтожается при последующем обновлении, как задано здесь: JSF 2.1. Метод ViewScopedBean @PreDestroy не называется. Я хочу знать, почему это так, что даже когда они истекают и больше не полезны, они все еще не разрушаются и, следовательно, продолжают потреблять память.

Ответ 1

Мне удалось найти чистую работу, используя аннотацию OmniFaces @ViewScoped (org.omnifaces.cdi.ViewScoped) вместо стандартного @ViewScoped (javax.faces.view.ViewScoped).

OmniFaces ViewScoped корректно уничтожает beans, как только они истекают.

Подробнее см. здесь: http://showcase.omnifaces.org/cdi/ViewScoped