我在视图Scoped Bean中有一个方法,带有@PreDestroy注释,另一个带有@PostConstruct注释.
@PostConstruct每次导航到使用此视图范围bean的页面时,都会正确调用该方法.
但是,当我导航到新页面(不使用此视图范围bean)时<h:link/>,@PreDestroy永远不会调用该方法.
我不是在谈论手动更改网址或会话结束,仅仅是导航案例.
我错过了什么?
提前致谢
编辑:这个问题提出的问题在codebulb.ch的这篇文章中得到了很好的解释和证实,包括JSF @ViewScoped,CDI @ViewSCoped和Omnifaces 之间的一些比较@ViewScoped,以及JSF @ViewScoped"设计漏洞" 的明确声明:5月24日, 2015 Java EE 7 Bean范围比较了2的第2部分
编辑:2017-12-05用于这个问题的测试用例仍然非常有用,但原始帖子(和图像)中关于垃圾收集的结论是基于JVisualVM,我发现它们无效.请改用NetBeans Profiler!现在我正在从NetBeans配置,而不是JVisualVM连接到GlassFish /似鲭水狼牙鱼,在这里我感到场得到引用(甚至@PreDestroy称为后)仍持有中强制GC的OmniFaces ViewScoped完全一致的结果与试验应用sessionListeners型的com.sun.web.server.WebContainerListener内ContainerBase$ContainerBackgroundProcessor,他们不会GC.
众所周知,在JSF2.2中,对于使用@ViewScoped bean的页面,使用以下任何一种技术导航(或重新加载)将导致@ViewScoped bean在会话中"悬空"的实例它不会被垃圾收集,导致堆内存不断增长(只要GET引发):
使用h:链接获取新页面.
使用h:outputLink(或HTML A标记)获取新页面.
使用RELOAD命令或按钮在浏览器中重新加载页面.
使用键盘重新加载页面在浏览器URL上输入ENTER(也是GET).
相比之下,通过使用一个h:commandButton来传递JSF导航系统会导致@ViewScoped bean的发布,从而可以对其进行垃圾回收.
这是由(由BalusC)在JSF 2.1上解释的.ViewScopedBean @PreDestroy方法未被我的小型NetBeans示例项目/sf/answers/2128728101/在JSF2.2和Mojarra 2.2.9中调用和演示,其中项目说明了各种导航案例,可在此处下载.(编辑:2015-05-28:完整代码现在也可以在下面找到.)
[编辑:2016-11-13现在还有一个改进的测试网络应用程序,包含完整的说明,@ViewScoped并在GitHub上与OmniFaces 和结果表进行比较:https://github.com/webelcomau/JSFviewScopedNav]
我在这里重复一个index.html的图像,它总结了导航案例和堆内存的结果:

问:如何检测由GET导航引起的这种"悬挂/悬挂"@ViewScoped bean并将其删除,或以其他方式呈现垃圾收集?
请注意,我不会在会话结束时询问如何清理它们,我已经看到了各种解决方案,我正在寻找在会话期间清理它们的方法,以便在会话期间堆内存不会过度增长由于无意中的GET导航.
在JBoss 7.1.1上的JavaEE6项目(EJB3,JSF2)中,似乎我们有@ViewScoped bean的内存泄漏.最后一天,我花时间在这个问题调查上.所以我创建了两个页面的简单项目,以保证在第一页离开@ViewScoped bean之后将被释放.
<context-param> //web.xml
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
<param-value>false</param-value>
</context-param>
Run Code Online (Sandbox Code Playgroud)
TreeBean.java
@ManagedBean
@ViewScoped
public class TreeBean implements Serializable {
private TreeNode root;
public static AtomicInteger count = new AtomicInteger(0);
@Override
protected void finalize() throws Throwable {
System.out.println("TreeBean beans count: " + count.decrementAndGet() + " (FINALISATION)");
}
public TreeBean() {
super();
System.out.println("TreeBean beans count: " + count.incrementAndGet() + " (INITIALISATION)");
}
Run Code Online (Sandbox Code Playgroud)
first.xhtml
....
<h:form id="frm">
<p:tree
value="#{treeBean.root}"
var="node"
id="tree">
....
<p:commandLink
action="second.xhtml?faces-redirect=true"
value="toSecond" />
....
Run Code Online (Sandbox Code Playgroud)
second.xhtml
....
<h:form …Run Code Online (Sandbox Code Playgroud) 在我们 在JBoss 7.1.1上的JavaEE6项目(EJB3,JSF2)中,似乎我们有SeamFaces的内存泄漏.@ViewScoped
我们制作了一个小原型来检查这个事实:
在测试结束时,我们使用VisualVM检查内存的内容,这里我们得到了:
@ViewScopedbean,我们仍然可以获得200个有状态实例MyController- 并且该@PreDestroy方法永远不会被调用;@ConversationScopedbean,@preDestroy方法称为会话结束,然后我们得到一个干净的内存.我们是否严重使用视图范围,还是真的是一个错误?
这是XHTML页面:
<!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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:s="http://jboss.org/seam/faces">
<f:metadata>
<f:viewParam name="u" value="#{myBean.uselessParam}" />
<s:viewAction action="#{myBean.callService}" />
</f:metadata>
<h:body >
<f:view>
</f:view>
</h:body>
</html>
Run Code Online (Sandbox Code Playgroud)
现在包含的bean myBean.对于@ConversationScoped变体,所有注释的部分都是未注释的.
@ViewScoped
// @ConversationScoped
@Named
public class MyBean implements Serializable
{
@Inject
MyController myController; …Run Code Online (Sandbox Code Playgroud) 我的问题与此(或其他)有关:
如此处所述,没有简单的解决方案来解决在导航时销毁视图范围的Bean的问题,并且在会话期满时似乎也是如此。
释放(调用该@PreDestroy方法)JSF视图范围的Bean 的非平凡方法会是什么样子,或者更确切地说,是会话期满后立即释放?
我在GlassFish 3.1.2上使用Java EE 6和Mojarra2.1.x。
jsf-2 ×5
view-scope ×4
jsf ×2
cdi ×1
glassfish ×1
heap-memory ×1
java-ee ×1
memory-leaks ×1
myfaces ×1
seam3 ×1
tomcat7 ×1