Web*_*ter 10 jsf garbage-collection heap-memory jsf-2 view-scope
编辑:这个问题提出的问题在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导航.
基本上,您希望在窗口卸载期间销毁JSF视图状态和所有视图范围的bean.该解决方案已在OmniFaces @ViewScoped注释中实现,该注释在其文档中充实,如下所示:
可能存在在
unload调用浏览器事件时立即销毁视图范围bean的情况.即用户通过GET导航或关闭浏览器选项卡/窗口时.两个JSF 2.2视图范围注释都不支持这一点.从OmniFaces 2.2开始,此CDI视图范围注释将保证@PreDestroy在浏览器卸载时也调用带注释的方法.这个技巧是通过自动包含的帮助程序脚本通过同步XHR请求完成的omnifaces:unload.js.然而,有一个小警告:在慢速网络和/或糟糕的服务器硬件上,卸载页面的最终用户操作与所需结果之间可能存在明显的滞后.如果这是不可取的,那么最好坚持使用JSF 2.2自己的视图范围注释并接受推迟的销毁.从OmniFaces 2.3开始,卸载进一步改进,以便在服务器端状态保存的情况下从JSF实现的内部LRU映射中物理移除关联的JSF视图状态,从而进一步降低
ViewExpiredException先前创建/打开的其他视图的风险.作为此更改的副作用,@PreDestroy在OmniFaces CDI视图作用域bean的同一视图中引用的任何标准JSF视图作用域bean 的带注释的方法也将保证在浏览器卸载时调用.
您可以在此处找到相关的源代码:
ViewScopeManager#registerUnloadScript()unload.unminified.jsOmniViewHandler#unloadView()Hacks#removeViewState()卸载脚本将在窗口beforeunload事件期间运行,除非它是由任何基于JSF的(ajax)表单提交引起的.至于commandlink和/或ajax提交,这是特定于实现的.目前, Mojarra,MyFaces和PrimeFaces受到认可.
卸载脚本将在现代浏览器上触发 navigator.sendBeacon并回退到同步XHR(异步将失败,因为页面可能比实际命中服务器的请求更快卸载).
var url = form.action;
var query = "omnifaces.event=unload&id=" + id + "&" + VIEW_STATE_PARAM + "=" + encodeURIComponent(form[VIEW_STATE_PARAM].value);
var contentType = "application/x-www-form-urlencoded";
if (navigator.sendBeacon) {
// Synchronous XHR is deprecated during unload event, modern browsers offer Beacon API for this which will basically fire-and-forget the request.
navigator.sendBeacon(url, new Blob([query], {type: contentType}));
}
else {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, false);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader("Content-Type", contentType);
xhr.send(query);
}
Run Code Online (Sandbox Code Playgroud)
卸载视图处理程序将显式销毁所有@ViewScopedbean,包括标准的JSF(请注意,只有在视图引用至少一个OmniFaces @ViewScopedbean 时才会初始化卸载脚本).
context.getApplication().publishEvent(context, PreDestroyViewMapEvent.class, UIViewRoot.class, createdView);
Run Code Online (Sandbox Code Playgroud)
但是,这不会破坏HTTP会话中的物理JSF视图状态,因此以下用例将失败:
com.sun.faces.numberOfLogicalViews上下文参数,在MyFaces中使用org.apache.myfaces.NUMBER_OF_VIEWS_IN_SESSION上下文参数).@ViewScopedbean 的页面.这将失败,ViewExpiredException因为之前关闭的选项卡的JSF视图状态在物理上没有被破坏PreDestroyViewMapEvent.他们仍然坚持参加会议.OmniFaces @ViewScoped实际上会摧毁它们.但是,销毁JSF视图状态是特定于实现的.这至少解释了Hacks类中应该实现的相当hacky代码.
对于这种特殊情况下的集成测试,可以发现ViewScopedIT#destroyViewState()在ViewScopedIT.xhtml其目前对WildFly 10.0.0,TomEE 7.0.1和似鲭水狼牙鱼4.1.1.163运行.
简而言之:只需更换javax.faces.view.ViewScoped的org.omnifaces.cdi.ViewScoped.其余的是透明的.
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
@Named
@ViewScoped
public class Bean implements Serializable {}
Run Code Online (Sandbox Code Playgroud)
我至少努力提出一种公共API方法来物理破坏JSF视图状态.也许它会出现在JSF 2.3中,然后我应该能够消除OmniFaces Hacks类中的样板.一旦OmniFaces中的东西被抛光,它可能最终会出现在JSF中,但不会出现在2.4之前.
| 归档时间: |
|
| 查看次数: |
3547 次 |
| 最近记录: |