JSF通过EL和复合组件泄漏内存

时间:2013-10-11 04:15:16

标签: jsf memory-leaks el composite-component

注意:我正在使用mojarra 2.1.20和丰富的面孔4.2.2。

我已经分析了一个堆转储,我注意到EL表达式驻留在会话中的LRUMap中。有谁知道为什么以及如何做以避免它?

我遇到的问题与包含以下行的复合组件有关:

  <rich:select ... valueChangeListener="#{cc.listValuesChangeListener}"

使用支持bean my.package.MultiComboSelection。显然my.package.MultiComboSelection有一个名为listValuesChangeListener的方法。

我看到的问题是LRUMap包含ContextualCompositeMethodExpression(上面的valueChangeListener表达式的表示),cc属性引用MultiComboSelection。 MultiComboSelection扩展了UINamingContainer,因此具有父/子属性 - 引用了组件树。

结果是16MB的内存不能被垃圾收集,因为有一个参考链:

  

会话而&GT; LRUMap-&GT; ContextualCompositeMethodExpression-&GT; MultiComboSelection-&GT;父   和16MB

问题是 - 为什么会发生这种情况以及如何解决或解决它?

Class Name                                                                                   | Shallow Heap | Retained Heap | Retained Heap
--------------------------------------------------------------------------------------------------------------------------------------------
my.package.MultiComboSelection @ 0x78dc2bd50                                                 |           96 |    16 466 272 |    16 466 272
|- component javax.faces.component.UIComponentBase$FacetsMap @ 0x78dbbbd58                   |           48 |           128 |              
|- parent javax.faces.component.UIPanel @ 0x78dbbbdd8                                        |           88 |           760 |              
|- cc com.sun.faces.facelets.el.ContextualCompositeMethodExpression @ 0x78dc2bce0            |           32 |    16 466 384 |              
|  |- [0] java.lang.Object[2] @ 0x78dc2bc90                                                  |           24 |    16 466 464 |              
|  |  '- [0] java.lang.Object[1] @ 0x78dc2bc78                                               |           24 |    16 466 488 |              
|  |     '- [0] java.lang.Object[5] @ 0x78dc2bc20                                            |           40 |    16 466 576 |              
|  |        '- [0] java.lang.Object[2] @ 0x78dc2bc08                                         |           24 |    16 466 600 |              
|  |           '- [0] java.lang.Object[4] @ 0x78dc2bbe8                                      |           32 |    16 466 632 |              
|  |              '- value java.util.HashMap$Entry @ 0x78dc2bb40                             |           32 |    16 466 800 |              
|  |                 '- [1579] java.util.HashMap$Entry[2048] @ 0x78dbf61b8                   |        8 208 |    33 552 536 |              
|  |                    '- table java.util.HashMap @ 0x78dbb6860                             |           48 |    33 552 584 |              
|  |                       '- [1] java.lang.Object[2] @ 0x78ad95340                          |           24 |    33 552 608 |              
|  |                          '- value java.util.LinkedHashMap$Entry @ 0x78ad952c0           |           40 |    33 552 736 |              
|  |                             |- after, before java.util.LinkedHashMap$Entry @ 0x78acbe6a0|           40 |            40 |              
|  |                             |- [0] java.util.HashMap$Entry[2] @ 0x78ad952a8             |           24 |            24 |              
|  |                             |  '- table com.sun.faces.util.LRUMap @ 0x78ad95270         |           56 |    33 552 856 |              
--------------------------------------------------------------------------------------------------------------------------------------------

3 个答案:

答案 0 :(得分:6)

ContextualCompositeMethodExpression将整个复合组件引用为实例变量,作为对issue 1462的修复的结果。用户已将此内存泄漏问题报告为issue 1940。然后,由于对issue 1943的修复,实例变量被标记为transient。然而,问题1940由于某种原因被标记为1943年的重复。两个用户在1940年问题的底部正确地评论了你的问题,内存泄漏问题仍然存在,但我没有看到任何新问题之后的相关报告。当复合组件包含任何方法表达式(如值更改侦听器)时,问题确实只会出现。

理论上,这个问题可以通过告诉Mojarra在会话中序列化视图状态而不是保持对视图状态的引用来解决。由于实例变量标记为transient,因此它将被绕过。您可以通过web.xml中的以下上下文参数来实现:

<context-param>
    <param-name>com.sun.faces.serializeServerState</param-name>
    <param-value>true</param-value>
</context-param>

再次,理论上;我没有测试过。

您可能也想尝试MyFaces,我无法告诉它会解决这个问题,但我知道MyFaces 2.x到目前为止通常比Mojarra更谨慎,因为状态管理,内存使用和性能

同时,我强烈建议为Mojarra创建一个新问题,引用问题1940,这个Stack Overflow问题和你的发现。在视图状态中引用UI组件绝对不对。 UI组件实例本质上是请求作用域,而不是视图作用域。


更新:重新报告为issue 3198,已在Mojarra 2.2.8中修复,并按照issue 3544在Mojarra 2.1.29中向后移植。因此,如果您升级到至少那些版本,那么当您不使用com.sun.faces.serializeServerState=true(或根据JSF 2.2的javax.faces.SERIALIZE_SERVER_STATE=true)时,应该修复此内存泄漏。

答案 1 :(得分:2)

我们的复合元素与actionListener有类似的问题。 Composite-Element收集了List DataObjects,尽管它们应该是garbageCollected。我们发现,在重新加载List之前list.clear()有助于防止此内存泄漏。

答案 2 :(得分:1)

这可能由https://java.net/jira/browse/JAVASERVERFACES-3544在Mojarra上修复。