Method profiling with short --loop causes unbounded MetaSpace and class count growth over time
Describe the bug
When running async-profiler with --trace option and a relatively short --loop option I noticed slow but steady increase of Metaspace size and class count.
For the production use case (Spring application/java 8) after 1 month of using method profiling:
- class count rose from 105k to 708k
- used Metaspace size rose from 1.16 GB to 3.73 GB
That started to have noticeable effect on GC pause time.
Production setup was profiling several methods with --trace option and had --loop 1m configured
Based on my production metrics analysis it seems that rate of MetaSpace and class count growth is correlated with the frequency of dumping jfr files (--loop option). Memory growth was much slower when I was using --loop 10m.
Restarting the application and disabling async-profiler, class count and Metaspaces size is flat again.
I'm able to reproduce the problem on spring-petclinic repository with Java 25 and within few minutes.
Expected vs. actual behavior
Expected behaviour Metaspace size and class count of the Java app remains stable when using method profiling
Actual behavior
Metaspace size and class count of the Java app slowly grows over time when using --trace options and dumping jfr files frequently with --loop option.
Reproduction Steps
- Clone, build and run spring petclinic
git clone https://github.com/spring-projects/spring-petclinic.git
cd spring-petclinic/
./gradlew build
./jdk-25.0.3+9/bin/java -XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=detail -jar build/libs/spring-petclinic-4.0.0-SNAPSHOT.jar- Simulate some application traffic
while true; do curl -v 'http://localhost:8080/owners/7'; done;- Start async-profiler
I've set -i and --loop params very low to quickly reproduce the problem.
./async-profiler-4.4-linux-x64/bin/asprof --loop 5s -f /tmp/%t.jfr --trace "org.springframework.samples.petclinic.owner.OwnerController.showOwner" $( jps | grep spring-petclinic | cut -d' ' -f1 )
- Check metaspace size:
jcmd $( jps | grep spring-petclinic | cut -d' ' -f1 ) VM.metaspace | head -5
3002434:
Metaspace used 96217K, committed 96960K, reserved 1179648K
class space used 13666K, committed 14016K, reserved 1048576K
Total Usage - 487 loaders, 20613 classes (1606 shared):- Wait ~10 minutes
- Check Metaspace again After few minutes, we can notice small growth of class count and Metaspace size. Based on my production observation this growth is unbounded.
jcmd $( jps | grep spring-petclinic | cut -d' ' -f1 ) VM.metaspace | head -5
3002434:
Metaspace used 99138K, committed 99840K, reserved 1179648K
class space used 14144K, committed 14464K, reserved 1048576K
Total Usage - 488 loaders, 21400 classes (1606 shared):
Additional Information/Context
No response
Async-profiler version
4.4 (reproduction), 4.3(first noticed)
Environment details
OS name: Linux
- reproduction: 6.12.91-1-MANJARO
- first noticed: RHEL 8
CPU architecture: x86_64
JDK version:
- reproduction: Eclipse Temurin JDK 25:
jdk-25.0.3+9 - first noticed: Eclipse Temurin JDK 8:
1.8.0_382-b05
- reproduction: Eclipse Temurin JDK 25:
Is an application running in a container: no
Source: async-profiler/async-profiler