UIData: Huge memory consumption for facets containing UIInput
See original GitHub issuePrimefaces: 8.0++
Description of the bug
Recently our server (WF 10) crashed with OOM exception. The heapdump revelead over 90mio instances of HashMap#Node
(consuming 4GB of heap space). Nearly 90% of those instances exists because of the state saving mechanism (50% of those nodes are filled with SavedState
instances).
It looks like that the facets
(like filter
) are stored per row-index instead of only one time.
Steps to reproduce
Reproducer: https://github.com/fanste/primefaces-test/tree/test-7369
- Add a breakpoint to PF’s UIData, line 481
- Open the index page
- Each time
setRowIndex
is called, UIData will save it’s state, which also iterates over the facets of each column. At some point you will see, that the componentID will contain the rowIndex which makes no sense for some facets.
Effectively it will generate an entry in the hashmap for each column times each row. Imagine you have a datatable with 50 columns and 50000 rows - that was the problem in our case.
I know that it makes no sense to display that many data at once. Therefor we used a datatable with pagination=true
. It seems that the user visitied each single page. Otherwise the map should not be flooded with SavedState
instances of each single row.
Issue Analytics
- State:
- Created 2 years ago
- Comments:10 (10 by maintainers)
Top GitHub Comments
Because the state map contains the component IDs of the filter’s UIInput multiple times - including the rowIndex:
f:dt:idOfFilter
vsf:dt:0:idOfFilter
,f:dt:1:idOfFilter
, …UIData#setRowIndex
>#setRowIndexWithoutRowStatePreserved
>#saveDescendantState
> iterates over children (here: column) and calls overloaded#saveDescendantState
> iterates over facets of that column.Because of
UIData#saveDescendantState
, the ID of each visited component is resetted. Therefore it also resets the ID of the facet components which than include the rowIndex in itsclientId
.It should be better than using a non-paged table which always will render all rows.
lazy
is not possible due to some customer requirements…I’ve just listed all occurences in that method. Detailed example: 1157 calls
setRowIndex
. Maybe a header row is used, thaninSameGroup
in line 1159 will do it again. IfinSameGroup
is not used, 1164 callssetRowIndex
again. It has nothing todo with the main problem it was just an additional observation and could be moved to some new optimization issue.Reproducer from #925: pf-925.zip
GET the page. Initial rendering yields the expected output: there is no current row in a header, but there is a column.
Now press the “submit” button. Observe the output: