Tôi có một câu hỏi liên quan đến vòng đời của đậu CDI phiên scoped.
Theo như tôi hiểu, một phiên CDI phạm vi đậu được xây dựng bởi container khi phiên bắt đầu và hủy khi phiên kết thúc. Trước khi đậu bị phá hủy, phương thức @PreDestroy được gọi như được mô tả ở đây https://docs.oracle.com/javaee/6/tutorial/doc/gmgkd.html. Nó cũng nói để giải phóng tài nguyên trong phương pháp này.
Đậu phạm vi phiên CDI không bị phá hủy kết quả trong rò rỉ bộ nhớ
Trong một ứng dụng JSF tôi xây dựng tôi kinh nghiệm Memory Leak vì đậu dường như không thể bị phá hủy và do đó @PreDestroy Phương pháp không được viện dẫn để giải phóng một số tài liệu tham khảo cho các nhà sưu tập rác. Vì vậy, tôi đã xây dựng một Ứng dụng đơn giản để kiểm tra hành vi. Kinh nghiệm của tôi là bean phiên không bị hủy khi phiên kết thúc và hơn nữa nó thậm chí không bị phá hủy khi không gian bộ nhớ là cần thiết. Tôi không thể tin rằng tôi là người đầu tiên gặp này, nhưng tôi không tìm thấy bất kỳ thông tin về hành vi này ..
Vì vậy, câu hỏi của tôi là: nên một bean CDI không bị hủy diệt - và do đó @PreDestroy Phương thức được gọi - ngay lập tức sau khi bối cảnh của nó hết hạn? Và nếu không nên nó ít nhất bị phá hủy khi không gian là cần thiết?
ứng dụng thử nghiệm của tôi:
Tôi không được phép đăng một bức tranh, nhưng đề cương là webapp JSF rất cơ bản được tạo ra bởi nhật thực. Tôi cũng có tệp 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>
tôi mở trang index.xhtml và @PostConstruct Phương thức được gọi như mong đợi. Không gian heap được vượt quá khi tôi gọi data_1 và data_2 cả mà không giải phóng ở giữa. Khi tôi giải phóng một trong các tài nguyên ở giữa hoặc tôi gọi một phương thức hai lần liên tiếp, không gian heap là đủ, vì bộ thu gom rác sẽ giải phóng bộ nhớ. Điều này hoạt động như tôi mong đợi nó hoạt động.
Nhưng khi tôi gọi một hàm dữ liệu, đóng trình duyệt và do đó phiên, mở trình duyệt mới và gọi lại một lần nữa, sau đó ứng dụng ngừng hoạt động như (tôi đoán) không gian bộ nhớ bị vượt quá . Vấn đề là: bean phiên đầu tiên không bị hủy và phương thức @PreDestroy của chúng ta không được gọi và do đó ArrayList vẫn còn trong bộ nhớ.
Ai đó có thể giải thích cho tôi điều gì đang xảy ra ở đây không? Không nên một hạt CDI bị phá hủy bởi container ngay sau khi bối cảnh của nó hết hạn để tham khảo có thể được thiết lập để null và thu gom rác có thể tài nguyên miễn phí?
Tôi đang sử dụng JBoss AS 7.1.1 và thực thi mặc định JSF Mojarra 2.1.
JBoss AS 7.1.1 là cổ đại. Ít nhất hãy thử phiên bản Weld hiện tại để loại trừ lỗi cố định đã biết và đã tồn tại từ nguyên nhân. – BalusC
Ok, cảm ơn bạn BalusC, tôi sẽ cố gắng và quay trở lại! –
Tôi đã nâng cấp triển khai WELD lên 1.1.23, nhưng nó không giúp ích gì. –