Skip to content

Fuseki sessions are immortal and fill up heap #4033

Description

@SamuelBoerlin

Version

6.1.0

What happened?

Hello

We observed Fuseki's heap memory usage climbing slowly, though consistently, while doing a long chain of sequential SPARQL UPDATE requests over Fuseki's HTTP API, and it looked like a memory leak and did eventually cause us to run into OutOfMemoryError repeatedly.

This prompted us to investigate and we found that the root cause to be that sessions seem to be immortal.
The reason this is especially problematic for us is because we use Shiro's authcBasic module and our backend authenticates on each request. This then causes unlimited sessions to pile up quite quickly in Fuseki.

I must preface that most of the analysis was done mostly by Claude Code, but it does look correct to me and the session "memory leak" was experimentally confirmed to be fixed by disabling session storage altogether in the shiro config with securityManager.subjectDAO.sessionStorageEvaluator.sessionStorageEnabled = false. Since then the heap usage remains low and constant, we're no longer running into OutOfMemoryError, and the heap now fits very comfortably in the same Xmx limit as before.

The analysis mainly consisted of running our workload for a while and then creating a heap dump with jmap. A significant portion of the heap, ~1.6GB, was attributed to ~1.23 M ManagedSession objects and the corresponding container ConcurrentHashMap. It was then concluded that sessions are immortal with the reason being that session lifetime is apparently never configured on the SessionHandler in FMod_Shiro. SessionHandler defaults to immortal sessions as inherited from AbstractSessionManager.

Is it correct that sessions are really immortal? If so, is that intentional?
Should this perhaps be configurable?

For us simply disabling session storage with securityManager.subjectDAO.sessionStorageEvaluator.sessionStorageEnabled = false might work because our backend authenticates on each request anyways, and this feature is documented at https://shiro.apache.org/session-management.html.
But is this really fine or could we run into problems by doing this? Just disabling all session storage seems like a heavy hammer, and I'm not yet sure how this will interact with Fuseki's web UI.

Best regards
Samuel

PS: perhaps this was also the root cause of #3432 because as far as I can tell FMod_Shiro was introduced between 5.2.0 and 5.5.0.

Relevant output and stacktrace

Class Name                                                           |    Objects |  Shallow Heap |    Retained Heap
---------------------------------------------------------------------------------------------------------------------
                                                                     |            |               |                 
byte[]                                                               |  4’384’892 |   289’031’584 |   >= 289’031’584
java.util.concurrent.ConcurrentHashMap$Node                          |  5’725’473 |   274’822’704 | >= 1’622’296’112
java.util.concurrent.ConcurrentHashMap$Node[]                        |  1’227’488 |   216’579’552 | >= 1’652’637’328
org.eclipse.jetty.session.SessionData                                |  1’227’124 |   147’254’880 |   >= 726’457’664
java.lang.String                                                     |  4’344’885 |   139’036’320 |   >= 413’159’864
java.util.concurrent.ConcurrentHashMap                               |  1’228’438 |   127’757’552 | >= 1’652’769’320
org.eclipse.jetty.session.ManagedSession                             |  1’227’124 |   127’620’896 | >= 1’403’459’344
java.util.concurrent.locks.ReentrantLock$NonfairSync                 |  1’227’422 |    58’916’256 |    >= 58’916’992
org.eclipse.jetty.session.SessionInactivityTimer                     |  1’227’124 |    58’901’952 |   >= 137’438’336
java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject|  1’227’254 |    49’090’160 |    >= 49’090’176
org.eclipse.jetty.session.SessionInactivityTimer$1                   |  1’227’124 |    49’084’960 |    >= 78’535’984
com.github.benmanes.caffeine.cache.PSMS                              |    781’639 |    43’771’784 |   >= 116’675’280
java.util.concurrent.CopyOnWriteArrayList                            |  1’227’332 |    39’274’624 |    >= 88’377’424
java.lang.Object[]                                                   |  1’248’661 |    31’863’416 |    >= 43’891’880
java.util.concurrent.atomic.AtomicReference                          |  1’239’536 |    29’748’864 |    >= 30’172’384
java.util.concurrent.locks.ReentrantLock                             |  1’227’422 |    29’458’128 |    >= 29’466’504
org.eclipse.jetty.util.thread.AutoLock                               |  1’227’232 |    29’453’568 |    >= 58’912’232
org.eclipse.jetty.ee11.servlet.SessionHandler$ServletSessionApi      |  1’227’124 |    29’450’976 |    >= 29’450’976
org.apache.jena.graph.impl.LiteralLabel                              |    346’091 |    24’918’552 |    >= 66’942’712
org.apache.jena.tdb2.store.NodeId                                    |    582’074 |    23’282’960 |    >= 23’283’688
java.lang.Object                                                     |  1’246’253 |    19’940’048 |    >= 19’940’104
long[]                                                               |        184 |    10’533’144 |    >= 10’533’144
org.apache.jena.graph.Node_Literal                                   |    346’091 |     8’306’184 |    >= 75’245’616
org.apache.jena.graph.Node_URI                                       |    236’551 |     5’677’224 |    >= 35’411’984
java.util.LinkedHashMap$Entry                                        |     37’615 |     2’407’360 |     >= 2’673’384
jdk.nio.zipfs.ZipFileSystem$IndexNode                                |     33’213 |     1’859’928 |     >= 4’646’736
char[]                                                               |      7’117 |     1’273’952 |     >= 1’273’952
java.util.HashMap$Node[]                                             |      2’420 |     1’162’352 |     >= 4’553’760
java.util.HashMap$Node                                               |     23’282 |     1’117’536 |     >= 3’469’776
int[]                                                                |      5’964 |     1’076’056 |     >= 1’076’056
java.nio.DirectByteBuffer                                            |      7’280 |       698’880 |       >= 698’952
java.util.ArrayList                                                  |     13’982 |       559’280 |    >= 11’684’440
Total: 32 of 16’742 entries; 16’710 more                             | 35’587’914 | 1’885’973’400 |                 
---------------------------------------------------------------------------------------------------------------------

Are you interested in making a pull request?

None

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions