Ich habe eine Frage in Bezug auf den Lebenszyklus von CDI Bohnen Session-Bereich.
Soweit ich verstehe, wird eine CDI-Session-Session-CD vom Container erstellt, wenn die Sitzung beginnt, und beim Beenden der Sitzung gelöscht. Bevor die Bean zerstört wird, wird die @ PreDestroy Methode wie hier beschrieben aufgerufen https://docs.oracle.com/javaee/6/tutorial/doc/gmgkd.html. Es heißt auch, Ressourcen in dieser Methode freizugeben.
CDI-Sitzung Bereich beanspruchte Bohne nicht zerstört führt zu Speicherverlust
In einer JSF-Anwendung, die ich baue ich Speicherverlust erfahren, weil die Bohne scheint nicht zerstört zu werden und damit die @PreDestroy Methode wird aufgerufen, nicht einige Hinweise für den Garbage Collector zu befreien. Also habe ich eine einfache Anwendung erstellt, um das Verhalten zu testen. Meine Erfahrung ist, dass die Session-Bean nicht zerstört wird, wenn die Sitzung vorbei ist und außerdem wird sie nicht zerstört, wenn der Speicherplatz benötigt wird. Ich kann nicht glauben, ich bin die erste Begegnung, aber ich habe keine Informationen zu diesem Verhalten findet ..
Also meine Frage ist: Sollte keine CDI Bean zerstört werden - und damit die @PreDestroy Methode aufgerufen werden - unmittelbar nachdem der Kontext abgelaufen ist? Und wenn nicht sollte es nicht zumindest zerstört werden, wenn der Platz benötigt wird?
Mein Test Anwendung:
Ich bin nicht ein Bild, um es erlaubt, aber der Umriss ist die sehr einfache JSF Webapp von Eclipse erzeugt. Ich habe auch die Datei 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>
ich die index.xhtml Seite öffnen und die @PostConstruct Die Methode wird wie erwartet aufgerufen. Der Heap-Speicherbereich wird überschritten, wenn ich daten_1 und daten_2 beide aufruft, ohne dazwischen zu arbeiten. Wenn ich eine der Ressourcen dazwischen freigebe oder eine Methode zweimal hintereinander aufrufe, reicht der Heapspeicher aus, da der Garbage Collector den Speicher freigibt. Das funktioniert so, wie ich es erwarten würde.
Aber wenn ich eine Datenfunktion aufrufen, schließen Sie den Browser und damit die Sitzung, öffnen Sie einen neuen Browser und rufen Sie eine der Datenfunktionen erneut auf, dann funktioniert die Anwendung als (ich denke) der Speicherplatz überschritten wird . Der Punkt ist: Die erste Session-Bean wird nicht zerstört und ihre @ PreDestroy Methode wird nicht aufgerufen und daher befindet sich die ArrayList noch im Speicher.
Kann mir bitte jemand erklären, was hier vor sich geht? Sollte eine CDI-Bean nicht durch den Container zerstört werden, sobald der Kontext abgelaufen ist, so dass Verweise auf null gesetzt werden können und der Garbage Collector Ressourcen freigeben kann?
Ich verwende JBoss AS 7.1.1 und seine Standardimplementierung JSF Mojarra 2.1.
JBoss AS 7.1.1 ist uralt. Versuche zumindest die aktuelle Weld-Version, um einen bekannten und bereits lange behobenen Fehler auszuschließen. – BalusC
Ok, danke BalusC, ich werde es versuchen und wiederkommen! –
Ich habe die WELD-Implementierung auf 1.1.23 aktualisiert, aber es hat nicht geholfen. –