JSF утечка памяти через EL и композитные компоненты
Примечание: я использую моджарру 2.1.20 и богатые лица 4.2.2.
Я проанализировал heapdump и заметил, что выражения EL находятся в сеансе в LRUMap. Кто-нибудь знает, почему и что нужно делать, чтобы этого избежать?
У меня проблема связана с составным компонентом, содержащим следующую строку:
<rich:select ... valueChangeListener="#{cc.listValuesChangeListener}"
с бином my.package.MultiComboSelection. Очевидно, у my.package.MultiComboSelection есть метод, определенный с именем listValuesChangeListener.
Проблема, которую я вижу, состоит в том, что LRUMap содержит ContextualCompositeMethodExpression (представление выражения для valueChangeListener выше), атрибут cc которого ссылается на MultiComboSelection. MultiComboSelection расширяет UINamingContainer и поэтому имеет свойства parent/children - ссылки на дерево компонентов.
В результате 16 МБ памяти невозможно собрать из-за мусора, поскольку существует цепочка ссылок:
session-> LRUMap-> ContextualCompositeMethodExpression-> MultiComboSelection-> parent и 16 МБ
Вопрос - почему это происходит и как это исправить или обойти это?
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 ответа
ContextualCompositeMethodExpression
ссылается на весь составной компонент как переменную экземпляра как следствие исправления ошибки 1462. Пользователь сообщил именно об этой проблеме утечки памяти как проблема 1940. И затем позже переменная экземпляра была отмечена transient
как следствие исправления к выпуску 1943 года. Тем не менее, выпуск 1940 года был по какой-то причине помечен как дубликат 1943 года. Два пользователя справедливо прокомментировали именно вашу проблему в нижней части выпуска 1940 года, что проблема утечки памяти все еще открыта, но я не вижу никаких новых сообщений о проблемах, связанных с к этому потом. Проблема действительно проявляется только тогда, когда составной компонент содержит любое выражение метода, например, слушатель изменения значения.
Теоретически, эту проблему можно обойти, сказав Моджарре сериализовать состояние представления в сеансе вместо сохранения ссылки на состояние представления. Как переменная экземпляра помечена 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, в отношении управления состоянием, использования памяти и производительности.
Тем временем я настоятельно рекомендую создать новую проблему для Мохарры, ссылаясь на проблему 1940 года, этот вопрос переполнения стека и ваши выводы. Ссылка на компоненты пользовательского интерфейса в состоянии просмотра определенно не подходит. Экземпляры компонентов пользовательского интерфейса по своей сути являются областью запроса, а не областью просмотра.
Обновление: это было повторно зарегистрировано как проблема 3198, которая исправлена в Мохарре 2.2.8 и как проблема 3544, портированная в Мохарре 2.1.29. Итак, если вы обновите хотя бы до этих версий, то эта утечка памяти, когда вы не используете com.sun.faces.serializeServerState=true
(или же javax.faces.SERIALIZE_SERVER_STATE=true
согласно JSF 2.2) должно быть исправлено.
У нас была похожая проблема с составным элементом с actionListener
, Композит-элемент собрал List
из DataObjects
, хотя они должны быть собраны. Мы обнаружили, list.clear()
Перед перезагрузкой Список помогает предотвратить утечку памяти.
Это, вероятно, исправлено https://java.net/jira/browse/JAVASERVERFACES-3544 на Мохарре.