cmunier opened a new issue, #1917: URL: https://github.com/apache/maven-mvnd/issues/1917
### Affected version 1.0.6 (also `mvnd-1.x` and `master`) ### Bug description After every build, `InvalidatingRealmCacheEventSpy` evicts the cached plugin and extension realms that refer to artifacts in the build tree. The caches then dispose these realms (`ClassWorld.disposeRealm`). This is needed for Maven plugins built in the same reactor. However, the disposed realms are never garbage collected. So with every build, the daemon keeps one more copy of the classes of each such plugin, and metaspace grows until `mvnd --stop`. The cause is in Sisu: the JSR250 `LifecycleManager` (enabled by Maven via `setJSR250Lifecycle(true)`) caches a lifecycle for every component class in a map with strong `Class` keys. When a realm is disposed, this cache is not flushed (eclipse-sisu/sisu-project#281, fix proposed in eclipse-sisu/sisu-project#282). Heap dump of a daemon after 3 builds, path to GC roots excluding weak/soft references: ``` org.codehaus.plexus.classworlds.realm.ClassRealm (plugin>…:<in-reactor-maven-plugin>:…, already disposed) |- <classloader> class <MojoClass> | |- key java.util.concurrent.ConcurrentHashMap$Node | | |- table java.util.concurrent.ConcurrentHashMap | | | |- lifecycles org.eclipse.sisu.bean.LifecycleManager | | | | |- delegate org.eclipse.sisu.plexus.PlexusLifecycleManager | | | | | |- plexusBeanManager org.codehaus.plexus.DefaultPlexusContainer | | | | | | |- container org.apache.maven.cli.DaemonMavenCli | | | | | | | |- cli org.mvndaemon.mvnd.daemon.Server ``` #### Reproducer The integration test project `integration-tests/src/test/projects/module-and-plugin` (one plugin module, one module using it). Run `mvnd clean install` several times in a fresh daemon. After each build, run `jcmd <pid> GC.run` and count the loaded `HelloMojo` classes with `jcmd <pid> VM.class_hierarchy`: | Build | 1 | 2 | 3 | 4 | |---|---|---|---|---| | `mvnd-1.x` (Maven 3.9.16) | 1 | 2 | 3 | 4 | | `master` (Maven 4.0.0-rc-7) | 1 | 2 | 3 | 4 | #### Impact in a real build The impact grows with the size of the realms. In a build with about 300 modules (Tycho, several in-reactor Maven plugins; one of them is used with 32 different `<dependencies>` sets, so it gets 32 realms per build), metaspace grew by about 0.75 GB per full build: | Build in the same daemon | 1 | 2 | 3 | 4 | 5 | 6 | |---|---|---|---|---|---|---| | Metaspace used after full GC | 1.05 GB | 1.79 GB | 2.54 GB | 3.28 GB | 4.02 GB | 4.76 GB | Partial builds that do not rebuild the in-reactor plugins reuse the cached realms and stay flat. With `-XX:MaxMetaspaceSize`, the `lowNonHeap` expiration can stop the daemon between builds, but a single build can also fail with `OutOfMemoryError: Metaspace` before that. In that build, plugins and extensions add more retention paths, which I reported separately: apache/maven#13794 (merged; `MavenSession` stored the current project in thread locals of pool threads), eclipse-tycho/tycho#6471 / #6472 and eclipse-tycho/tycho#6473 / #6474. The Sisu cache is the one that affects every in-reactor plugin, with or without such extensions. #### Proposed fix The real fix belongs in Sisu (eclipse-sisu/sisu-project#282). mvnd gets Sisu with the embedded Maven distribution (Sisu 1.1.0 on `master` with Maven 4.0.0-rc-7, 1.0.0 on `mvnd-1.x` with Maven 3.9.16), so it will take a Sisu release, a Maven release and a Maven update in mvnd until the Sisu fix arrives; for Maven 3.9.x maybe never. As a workaround until then, mvnd can flush the cache itself when it evicts a realm: `LifecycleManager.flushCacheFor(clazz -> clazz.getClassLoader() == realm)`. This method exists in Sisu since 0.9.0.M3 for this purpose. With this change, the counts above stay at 0 after every build. PR for `master`: <tbd>. I can port it to `mvnd-1.x`, if you agree. --- AI disclosure: the analysis and this issue text were prepared with the help of an AI assistant (Claude Code, Claude Opus 5.5, interactive). I have reviewed the content and verified the findings. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
