В Glassfish создается лишний SFSB, что приводит к утечке памяти
Я пытаюсь внедрить один SFSB в базовый компонент ViewScoped JSF в Glassfish 3.1.1.
Мой журнал показывает, что созданы ДВА SFSB, хотя только вторая получает:
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@f48cde0
INFO: constructed a new sfsb: com.exmaple.test.service.impl._TestSFSBImpl_Serializable@13dbf5ce
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@4de6b191
Позже, когда я ухожу, и бин ViewScoped выходит из области видимости, я вызываю remove() на SFSB, и поэтому я вижу это в журнале:
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@4de6b191
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@13dbf5ce
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@13dbf5ce
Но лишний первый конец, заканчивающийся на @f48cde0, никогда не вставлялся, поэтому у меня нет дескриптора, и он никогда не удаляется. Только позже, когда я выключаю сервер, я вижу, что он удален.
Вот мой код:
Бэк-бэк:
package com.example.test.ui;
import java.io.Serializable;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.event.AjaxBehaviorEvent;
import com.example.test.service.api.TestSFSB;
@ManagedBean(name = "testViewScopedSFSB")
@ViewScoped
public class TestViewScopedSFSB implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(TestViewScopedSFSB.class.getCanonicalName());
@EJB
private TestSFSB testSFSB;
@PostConstruct
public void postConstruct() {
LOGGER.info("constructed a new view scoped bean: " + this);
}
public int getNumClicks() {
return testSFSB.getNumClicks();
}
public void clicked(AjaxBehaviorEvent event) {
testSFSB.clicked();
}
@PreDestroy
public void preDestroy() {
LOGGER.info("destroying view scoped bean: " + this);
testSFSB.remove();
}
}
Интерфейс SFSB:
package com.example.test.service.api;
public interface TestSFSB {
void clicked();
int getNumClicks();
void remove();
}
Реализация SFSB:
package com.example.test.service.impl;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Local;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import com.example.test.service.api.TestSFSB;
@Stateful
@Local(TestSFSB.class)
public class TestSFSBImpl implements TestSFSB {
private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(TestSFSBImpl.class.getCanonicalName());
int numClicks = 0;
@PostConstruct
public void postConstruct() {
LOGGER.info("constructed a new sfsb: " + this);
}
@Override
public void clicked() {
numClicks++;
}
@Override
public int getNumClicks() {
return numClicks;
}
@Override
@Remove
public void remove() {
LOGGER.info("removing sfsb: " + this);
}
@PreDestroy
public void preDestroy() {
LOGGER.info("destroying sfsb: " + this);
}
}
И, наконец, страница JSF:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<h:html xmlns="http://www.w3.org/1999/xhtml"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
</h:head>
<h:body>
<h:form>
<h:commandLink action="/public/publicResource.jsf" value="Home" />
<h:panelGrid id="panel1">
<h:commandButton value="Click me">
<f:ajax event="click" listener="#{testViewScopedSFSB.clicked}"
render="panel1" />
</h:commandButton>
<h:outputText value="#{testViewScopedSFSB.numClicks}" />
</h:panelGrid>
</h:form>
</h:body>
</h:html>
Это такая простая настройка... какого черта это может быть? Ошибка в Glassfish возможно?
РЕДАКТИРОВАТЬ: Для того, чтобы развеять любые "сомнения" в правдивости того, что я сообщаю, вот журнал, когда я загружаю страницу 10 раз. Заметьте, что создано 20 SFSB, 2 каждый раз, но только одна очищена, когда я ухожу.
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@561b0019
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@2767c7d9
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@7b239469
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@7b239469
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@2767c7d9
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@2767c7d9
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@5c8608b9
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@63a6d923
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@5ef9bbf1
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@5ef9bbf1
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@63a6d923
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@63a6d923
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@31a4ef37
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@43551d57
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@8f95d4a
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@8f95d4a
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@43551d57
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@43551d57
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@69e3f60e
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@5f91e550
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@63661834
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@63661834
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@5f91e550
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@5f91e550
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@266c4c10
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@ff5c225
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@4f9d1352
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@4f9d1352
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@ff5c225
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@ff5c225
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@42650c3b
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@7806178a
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@57f3a295
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@57f3a295
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@7806178a
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@7806178a
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@70879d38
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@5763013f
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@24e6fbeb
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@24e6fbeb
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@5763013f
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@5763013f
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@49649260
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@552ee43b
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@798a092d
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@798a092d
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@552ee43b
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@552ee43b
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@1a722605
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@3c1e1fd3
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@5dbb747a
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@5dbb747a
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@3c1e1fd3
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@3c1e1fd3
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@21da38c0
INFO: constructed a new sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@7dc3d69c
INFO: constructed a new view scoped bean: com.example.test.ui.TestViewScopedSFSB@443edc45
INFO: destroying view scoped bean: com.example.test.ui.TestViewScopedSFSB@443edc45
INFO: removing sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@7dc3d69c
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@7dc3d69c
И, наконец, когда я выгружаю приложение, обратите внимание, что 10 лишних SFSB наконец уничтожаются:
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@561b0019
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@5c8608b9
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@31a4ef37
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@69e3f60e
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@266c4c10
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@42650c3b
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@70879d38
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@49649260
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@1a722605
INFO: destroying sfsb: com.example.test.service.impl._TestSFSBImpl_Serializable@21da38c0
Поверьте мне на слово, исходя из моей репутации, что поведение соответствует 100 ударам, вызывающим 200 бинов по одной схеме.
1 ответ
Это не ошибка, это особенность. И важный. В Java EE контейнер создает несколько экземпляров различных вещей (таких как bean-компоненты без состояния, bean-объекты, управляемые сообщениями, сущности и sfsbs), а также объединяет их в пулы и цепляет их, а что нет. Разрешение контейнеру делать и обрабатывать это - одна из причин использования Java EE. Вы можете настроить это поведение в большинстве контейнеров.
Из документации Glassfish:
Кроме того, сервер GlassFish поддерживает ряд настраиваемых параметров, которые могут контролировать количество кэшируемых "сохраняющих состояние" экземпляров (сессионных компонентов с сохранением состояния и объектов), а также продолжительность их кэширования.
[..]
Одним из наиболее важных параметров для пула GlassFish Server является постоянный размер пула. Если для устойчивого размера пула задано значение больше 0, контейнер не только предварительно заполняет пул компонентов указанным числом компонентов, но также пытается обеспечить постоянное наличие этого количества компонентов в свободном пуле. Это гарантирует, что в состоянии готовности к обработке достаточно компонентов для обработки пользовательских запросов.
( http://docs.oracle.com/cd/E18930_01/html/821-2418/beahn.html)
Если вы не хотите этого поведения, вы можете настроить его: прочитайте и перейдите по соответствующим ссылкам по ссылке выше.