[ 
https://issues.apache.org/jira/browse/GROOVY-12142?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18105189#comment-18105189
 ] 

ASF GitHub Bot commented on GROOVY-12142:
-----------------------------------------

paulk-asert opened a new pull request, #2798:
URL: https://github.com/apache/groovy/pull/2798

   …r and DFA-cache-cleaner threads, restore the ClassValue escape hatch
   
   A Groovy copy deployed per webapp (the common Tomcat/WEB-INF/lib topology) 
permanently pinned its class loader, growing metaspace on every parallel 
(re)deployment. Three independent pins:
   
   1. PIC-Cleaner: linking any indy call site started a never-terminating 
daemon thread from CacheableCallSite's static initializer, pinning the defining 
loader and capturing the creating context's protection domains. Stale PIC 
entries are now swept inline — both callers already hold the lruCache monitor 
and the cache is bounded (8), so the sweep is trivial; the 
groovy.indy.callsite.cleaner.inline flag (GROOVY-12092) is gone along with the 
thread it toggled, which also removes the parked-thread false positive it 
existed to avoid.
   
   2. DFA-cache-cleaner: each AtnManager started a never-terminating 
reference-queue thread whose catch-all swallowed even interrupts. The softly 
referenced AtnWrapper is a GC canary; its collection is now detected on the 
parse path when the soft reference reads null, clearing the shared DFA cache at 
the next parse instead of at GC time — no queue, no thread.
   
   3. java.lang.ClassValue associations on immortal (bootstrap) classes never 
release their value's class loader (JDK-8136353), so one dynamic dispatch on 
e.g. String pinned the loader. The groovy.use.classvalue=false escape hatch 
(present through 4.x, lost in the GROOVY-11520 collections cleanup) is 
restored, with the fallback rebuilt on ManagedIdentityConcurrentMap (~40 lines) 
rather than the removed deprecated collections. Default stays ClassValue.
   
   With 1+2 fixed, a dropped loader is collectable either with the flag or with 
a shutdown sweep over ClassInfo.getAllClassInfo() calling ClassInfo.remove — 
both verified by classloader-churn harness against the rebuilt jar; 
out-of-the-box default config still requires one of the two (the JVM bug is not 
ours to fix).




> Metaspace memory leak with parallel deployments on Tomcat
> ---------------------------------------------------------
>
>                 Key: GROOVY-12142
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12142
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 4.0.24, 4.0.29
>         Environment: Tomcat: 10.1.55
> openjdk version "17.0.19" 2026-04-21 LTS
> OpenJDK Runtime Environment (Red_Hat-17.0.19.0.10-1) (build 17.0.19+10-LTS)
> OpenJDK 64-Bit Server VM (Red_Hat-17.0.19.0.10-1) (build 17.0.19+10-LTS, 
> mixed mode, sharing)
>            Reporter: Jan Gosmann
>            Priority: Major
>         Attachments: Screenshot 2026-07-09 at 09.46.46.png, spring-test.tar.gz
>
>
> We are using [Tomcat parallel 
> deployments|https://tomcat.apache.org/tomcat-10.0-doc/config/context.html#Parallel_deployment]
>  to achieve downtimeless deployments. However, we with each new deployment 
> the metaspace grows (see attached image). Even after undeploying the old 
> version it does not shrink. If we configure a maximum metaspace size, new 
> parallel deployments fail with an out-of-memory error.
> I was able to reproduce this with a very simple Spring Boot application 
> (attached). As long as I had no Groovy in there, metaspace was reclaimed 
> before hitting the maximum on new deploys. After introducing Groovy, 
> metaspace is no longer reclaimed.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to