Repository: quarkusio/quarkus
Issue: Classloader leak in MP ContextManagerProvider / Smallrye SmallRyeContextManagerProvider

### Describe the bug

When running a Quarkus application in dev-mode, at each code reload an additional copy of the application is loaded in memory, but old classloaders are not being released in full, leading to exhausting both heap memory and metaspace after some reloads.

This is the patch to GC root, the classloader which should have been removed on the top:

```
Class Name                                                                                                | Shallow Heap | Retained Heap
-----------------------------------------------------------------------------------------------------------------------------------------
io.quarkus.bootstrap.classloading.QuarkusClassLoader @ 0x41a03c490                                        |          128 |       314,552
'- key java.util.HashMap$Node @ 0x41bc4dc28                                                               |           32 |         1,016
   '- [6] java.util.HashMap$Node[16] @ 0x415b7c388                                                        |           80 |     1,540,800
      '- table java.util.HashMap @ 0x415b7c358                                                            |           48 |     1,540,848
         '- contextManagersForClassLoader io.smallrye.context.SmallRyeContextManagerProvider @ 0x415b7c348|           16 |     1,540,864
            '- value java.util.concurrent.atomic.AtomicReference @ 0x415b7c338                            |           16 |     1,540,880
               '- INSTANCE class org.eclipse.microprofile.context.spi.ContextManagerProvider @ 0x415b7c2c0|            8 |     1,540,944
                  '- [227] java.lang.Object[5120] @ 0x41f8fba18                                           |       20,496 |     2,172,536
                     '- elementData java.util.Vector @ 0x417ce1560                                        |           32 |     2,172,568
                        '- classes io.quarkus.bootstrap.classloading.QuarkusClassLoader @ 0x417ce1368     |          128 |     9,650,128
-----------------------------------------------------------------------------------------------------------------------------------------

```

### Expected behavior

_No response_

### Actual behavior

_No response_

### How to Reproduce?

Open the `hibernate-orm-quickstart` from the quickstarts, run it in dev-mode and trigger live reloading N times.

Then connect a heap dump analyzer, you'll find N copies of all application classes.

### Output of `uname -a` or `ver`

_No response_

### Output of `java -version`

_No response_

### GraalVM version (if different from Java)

_No response_

### Quarkus version or git rev

`b470a90cf3`

### Build tool (ie. output of `mvnw --version` or `gradlew --version`)

_No response_

### Additional information

_No response_

Changed files:
extensions/smallrye-context-propagation/deployment/src/main/java/io/quarkus/smallrye/context/deployment/SmallRyeContextPropagationProcessor.java
extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java

diff --git a/extensions/smallrye-context-propagation/deployment/src/main/java/io/quarkus/smallrye/context/deployment/SmallRyeContextPropagationProcessor.java b/extensions/smallrye-context-propagation/deployment/src/main/java/io/quarkus/smallrye/context/deployment/SmallRyeContextPropagationProcessor.java
index a74e825dbf2..2e124d4e412 100644
--- a/extensions/smallrye-context-propagation/deployment/src/main/java/io/quarkus/smallrye/context/deployment/SmallRyeContextPropagationProcessor.java
+++ b/extensions/smallrye-context-propagation/deployment/src/main/java/io/quarkus/smallrye/context/deployment/SmallRyeContextPropagationProcessor.java
@@ -19,6 +19,7 @@
 import io.quarkus.deployment.annotations.Record;
 import io.quarkus.deployment.builditem.ExecutorBuildItem;
 import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
 import io.quarkus.deployment.util.ServiceUtil;
 import io.quarkus.smallrye.context.runtime.SmallRyeContextPropagationProvider;
 import io.quarkus.smallrye.context.runtime.SmallRyeContextPropagationRecorder;
@@ -67,11 +68,12 @@ void buildStatic(SmallRyeContextPropagationRecorder recorder)
     @Record(ExecutionTime.RUNTIME_INIT)
     void build(SmallRyeContextPropagationRecorder recorder,
             ExecutorBuildItem executorBuildItem,
+            ShutdownContextBuildItem shutdownContextBuildItem,
             BuildProducer<FeatureBuildItem> feature,
             BuildProducer<SyntheticBeanBuildItem> syntheticBeans) {
         feature.produce(new FeatureBuildItem(Feature.SMALLRYE_CONTEXT_PROPAGATION));
 
-        recorder.configureRuntime(executorBuildItem.getExecutorProxy());
+        recorder.configureRuntime(executorBuildItem.getExecutorProxy(), shutdownContextBuildItem);
 
         // Synthetic bean for ManagedExecutor
         syntheticBeans.produce(
diff --git a/extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java b/extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java
index def1211fa46..8451084b80f 100644
--- a/extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java
+++ b/extensions/smallrye-context-propagation/runtime/src/main/java/io/quarkus/smallrye/context/runtime/SmallRyeContextPropagationRecorder.java
@@ -10,6 +10,7 @@
 import org.eclipse.microprofile.context.spi.ThreadContextProvider;
 
 import io.quarkus.arc.Arc;
+import io.quarkus.runtime.ShutdownContext;
 import io.quarkus.runtime.annotations.Recorder;
 import io.smallrye.context.SmallRyeContextManager;
 import io.smallrye.context.SmallRyeContextManagerProvider;
@@ -40,7 +41,7 @@ public void configureStaticInit(List<ThreadContextProvider> discoveredProviders,
         builder.withContextManagerExtensions(discoveredExtensions.toArray(new ContextManagerExtension[0]));
     }
 
-    public void configureRuntime(ExecutorService executorService) {
+    public void configureRuntime(ExecutorService executorService, ShutdownContext shutdownContext) {
         // associate the static init manager to the runtime CL
         ContextManagerProvider contextManagerProvider = ContextManagerProvider.instance();
         // finish building our manager
@@ -49,6 +50,12 @@ public void configureRuntime(ExecutorService executorService) {
         SmallRyeContextManager contextManager = builder.build();
 
         contextManagerProvider.registerContextManager(contextManager, Thread.currentThread().getContextClassLoader());
+        shutdownContext.addShutdownTask(new Runnable() {
+            @Override
+            public void run() {
+                contextManagerProvider.releaseContextManager(contextManager);
+            }
+        });
     }
 
     public Supplier<Object> initializeManagedExecutor(ExecutorService executorService) {