Repository: quarkusio/quarkus
Issue: Memory leak in non-quarkus main() in quarkus-using module (due to quarkus dependencies)

To reproduce, take any quarkus quickstart and add this class in `src/test/java` (or `src/main/java`):

```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingMemoryLeakMain {

    protected static final Logger logger = LoggerFactory.getLogger(LoggingMemoryLeakMain.class);

    public static void main(String[] args) {
        for (int i = 0; i < 1_000_000_000; i++) {
            System.out.println("Sout iteration " + i);
            if (i % 1_000_000 == 0) {
                logger.info("Iteration {}", i);
            } else if (i % 1_000 == 0) {
                logger.debug("Iteration {}", i);
            } else {
                logger.trace("Iteration {}", i);
            }
        }
    }

}
```
With JDK 11, I get this:

```
Sout iteration 21071313
Sout iteration 21071314

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
```
That takes a few minutes. Use `-Xmx64m` to get it in a few seconds.
Its caused by jboss logging that by default remembers all logging statements in memory, see https://quarkusio.zulipchat.com/#narrow/stream/187030-users/topic/Memory.20leak.2C.20logging.20and.20psvm

**This memory leak might also affects unit tests that don't use quarkus integration.**

Why is this a problem?
It's often useful to add plain old mains in a quarkus module too, without having to create yet another module for them. These do not replace the Quarkus main that is the actually application. Examples include:

- to run a benchmark
- to experiment with a new library before mixing Quarkus in the complexity mix
- to run a tool such as converting adoc into html that goes in META-INF/resources, etc.
- ...

All of these have alternative ways of accomplishing that goal, which are better but more work intensive: it's easier to temporary just add a plain-java main and it's very _surprising_ that quarkus crippled that with a memory leak. It doesn't abide by the principle of least surprise.

Changed files:
independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/logging/QuarkusDelayedHandler.java

diff --git a/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/logging/QuarkusDelayedHandler.java b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/logging/QuarkusDelayedHandler.java
index 6fe4b7ed492..ae28d6fc633 100644
--- a/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/logging/QuarkusDelayedHandler.java
+++ b/independent-projects/bootstrap/runner/src/main/java/io/quarkus/bootstrap/logging/QuarkusDelayedHandler.java
@@ -18,6 +18,7 @@
 
 import java.util.ArrayDeque;
 import java.util.Deque;
+import java.util.logging.ErrorManager;
 import java.util.logging.Formatter;
 import java.util.logging.Handler;
 import java.util.logging.Logger;
@@ -36,10 +37,19 @@ public class QuarkusDelayedHandler extends ExtHandler {
 
     private final Deque<ExtLogRecord> logRecords = new ArrayDeque<>();
 
+    private final int queueLimit;
     private volatile boolean buildTimeLoggingActivated = false;
     private volatile boolean activated = false;
     private volatile boolean callerCalculationRequired = false;
 
+    public QuarkusDelayedHandler() {
+        this(4000);
+    }
+
+    public QuarkusDelayedHandler(final int queueLimit) {
+        this.queueLimit = queueLimit;
+    }
+
     @Override
     protected void doPublish(final ExtLogRecord record) {
         // If activated just delegate
@@ -53,6 +63,13 @@ protected void doPublish(final ExtLogRecord record) {
                     publishToNestedHandlers(record);
                     super.doPublish(record);
                 } else {
+                    // Determine whether the queue was overrun
+                    if (logRecords.size() >= queueLimit) {
+                        reportError(
+                                "The delayed handler's queue was overrun and log record(s) were lost. Did you forget to configure logging?",
+                                null, ErrorManager.WRITE_FAILURE);
+                        return;
+                    }
                     // Determine if we need to calculate the caller information before we queue the record
                     if (isCallerCalculationRequired()) {
                         // prepare record to move to another thread