У меня есть вопрос относительно жизненного цикла бинов CDI с сессией.
Насколько я понимаю, бит CDI, обработанный сеансом, сконфигурирован контейнером, когда сеанс начинается и уничтожается при завершении сеанса. Перед уничтожением bean-компонента @PreDestroy Метод вызывается, как описано здесь https://docs.oracle.com/javaee/6/tutorial/doc/gmgkd.html. В нем также говорится о выпуске ресурсов в этом методе.
Сессия, обработанная сеансом связи CDI, не разрушена, что приводит к утечке памяти
В приложении JSF я строй я переживаю утечку памяти, так как фасоль, кажется, не будет разрушена, и, следовательно, @PreDestroy метод не вызывается, чтобы освободить некоторые ссылки для сборщика мусора. Поэтому я создал простое приложение для тестирования поведения. Мой опыт в том, что сеансовый компонент не разрушается, когда сеанс завершен, и, кроме того, он даже не уничтожается, когда требуется пространство памяти. Я не могу поверить, что я первый столкнуться с этим, но я не нахожу никакой информации об этом поведении ..
Так что мой вопрос: не должен ли CDI боб быть разрушен - и, следовательно, @PreDestroy Вызывается метод - сразу после истечения срока его использования? И если это не должно быть, по крайней мере, уничтожено, когда пространство необходимо?
Мой тест Применение:
Я не разрешается размещать изображения, но план является очень простой JSF WebApp генерируется затмение. У меня также есть файл beans.xml.
Test.java:
package com.test;
import java.io.Serializable;
import java.util.ArrayList;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
@SessionScoped
@Named
public class Test implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String test;
private ArrayList<ComplexType> cps;
private ArrayList<ComplexType> cps_2;
@PostConstruct
public void init() {
System.out.println("test postconstruct..");
test = "Cdi Test";
}
@PreDestroy
public void cleanUp() {
cps = null;
cps_2 = null;
System.out.println("test cleanUp....");
}
public void data_1() {
cps = new ArrayList<ComplexType>();
for(int i = 0; i < 800; i++) {
String[] s = new String[100000];
ComplexType cp = new ComplexType(i, s);
cps.add(cp);
System.out.println(i);
}
System.out.println("data_1");
}
public void free_1() {
cps = null;
System.out.println("free_1");
}
public void data_2() {
cps_2 = new ArrayList<ComplexType>();
for(int i = 0; i < 800; i++) {
String[] s = new String[100000];
ComplexType cp = new ComplexType(i, s);
cps_2.add(cp);
System.out.println(i);
}
System.out.println("data_1");
}
public void free_2() {
cps_2 = null;
System.out.println("free_1");
}
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}
ComplexType.java:
package com.test;
public class ComplexType {
private int id;
private String[] name;
public ComplexType(int id, String[] name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String[] getName() {
return name;
}
public void setName(String[] name) {
this.name = name;
}
}
index.xhtml:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
>
<h:head>
<title>Cdi test </title>
</h:head>
<h:body>
<h:outputText value="#{test.test}"></h:outputText>
<h:form>
<h:commandButton value="cp_1 data" actionListener="#{test.data_1}">
<f:ajax></f:ajax>
</h:commandButton>
<h:commandButton value="cp_1 Free" actionListener="#{test.free_1}">
<f:ajax></f:ajax>
</h:commandButton>
<br></br>
<h:commandButton value="cp_2 data" actionListener="#{test.data_2}">
<f:ajax></f:ajax>
</h:commandButton>
<h:commandButton value="cp_2 Free" actionListener="#{test.free_2}">
<f:ajax></f:ajax>
</h:commandButton>
</h:form>
</h:body>
</html>
открыть страницу index.xhtml и @PostConstruct Метод вызывается, как ожидалось. Пространство кучи превышено, когда я вызываю data_1 и data_2 без освобождения между ними. Когда я освобождаю один из ресурсов между ними или я вызываю один метод дважды подряд, достаточно места кучи, поскольку сборщик мусора освобождает память. Это работает так, как я ожидаю, что он сработает.
Но когда я вызываю одну функцию данных, закройте браузер и, следовательно, сеанс, откройте новый браузер и снова вызовите одну из функций данных, тогда приложение перестает работать, поскольку (я думаю), объем памяти превышен , Дело в том, что первый сеансовый компонент не уничтожается и его @PreDestroy Метод не вызывается, и поэтому ArrayList все еще находится в памяти.
Может кто-нибудь, пожалуйста, объясните мне, что здесь происходит? Не следует ли уничтожить контейнер CDI контейнером, как только его контекст истечет, так что ссылки могут быть установлены равными нулю, а сборщик мусора может освобождать ресурсы?
Я использую JBoss AS 7.1.1 и его реализацию по умолчанию JSF Mojarra 2.1.
JBoss AS 7.1.1 древний. По крайней мере, попробуйте текущую версию Weld, чтобы исключить из-за известной и уже давно исправленной ошибки. – BalusC
Хорошо, спасибо BalusC, я попробую это и вернусь! –
Я обновил реализацию WELD до 1.1.23, но это не помогло. –