| Bug #118528 | Connector/J Memory Leak Problem | ||
|---|---|---|---|
| Submitted: | 26 Jun 2025 8:43 | Modified: | 12 Mar 0:01 |
| Reporter: | ünal polat | Email Updates: | |
| Status: | Open | Impact on me: | |
| Category: | Connector / J | Severity: | S3 (Non-critical) |
| Version: | 9.1.0 | OS: | Any |
| Assigned to: | Assigned Account | CPU Architecture: | Any |
| Tags: | Connector/J, memory-leak | ||
[26 Jun 2025 8:43]
ünal polat
[8 Jul 2025 19:55]
Filipe Silva
Hi Ünal Polat, Thank you for your interest in MySQL Connector/J and for taking the time to report this issue. As it stands, the current implementation doesn't require the spans map to be explicitly cleared. The use of a WeakHashMap in combination with the garbage collector is intended to handle this automatically. The fix you suggested doesn’t have a meaningful effect, as it would only remove a single entry from the map—the one corresponding to the span promoted as a link target (i.e., the connection creation span). All other spans are short-lived and, once the operation is complete, no strong references remain. As such, they should be eligible for garbage collection and automatically removed from the map. Are you certain that the garbage collector is not cleaning up the spans map? In my observations, this behavior appears to be working as expected. Would you be able to provide a minimal test case that reproduces the issue without involving Spring Boot? Ideally, it would include only Connector/J, OpenTelemetry, and a bit of test code to help isolate the behavior. Also, please use the latest MySQL Connector/J version.
[9 Aug 2025 1:00]
Bugs System
No feedback was provided for this bug for over a month, so it is being suspended automatically. If you are able to provide the information that was originally requested, please do so and change the status of the bug back to "Open".
[11 Mar 19:34]
Saurabh Anand
Facing the same issue. OpenTelemetryHandler maintains a WeakHashMap field named spans. When a connection is closed via Connection.close() or try-with-resources, this map is not cleared. After closure, 1 entry remains permanently in the map and is never reclaimed, neither by close() nor by repeated System.gc() calls. This is a deterministic per-connection memory leak. In long-running applications, full GC cycles are infrequent by design; the WeakHashMap entries that GC can collect sit unreleased for extended periods, and the 1 entry GC cannot collect accumulates permanently, making the "GC will handle it" assumption incorrect for production workloads.
[11 Mar 19:36]
Saurabh Anand
Adding Simple Java code to reproduce the issue, via attached file.
Proposed solution :
Three coordinated changes are required. A single spans.remove() in removeLinkTarget() is insufficient because spans accumulates entries beyond the connectionSpan, all telemetry state for a connection must be released at close time.
1. TelemetryHandler interface — add close() default no-op:
default void close() {
// no-op
}
2. OpenTelemetryHandler — implement close():
@Override
public void close() {
this.spans.clear();
this.linkTargets.clear();
}
3. ConnectionImpl.doClose() — call handler.close() before replacing with no-op:
TelemetryHandler handler = this.session.getTelemetryHandler();
handler.removeLinkTarget(this.connectionSpan);
handler.close();
this.session.setTelemetryHandler(NoopTelemetryHandler.getInstance());
This ensures all telemetry state is released deterministically at connection close, before the handler reference is dropped. No GC dependency, no WeakHashMap eviction race.
Tested with local patch and it releases the resources at connection.close(). Happy to submit a patch if required.
[11 Mar 19:49]
Saurabh Anand
Github link for code to reproduce the leak: https://github.com/iSaurabhAnand/connectorJ-Leak/blob/main/src/main/java/com/example/OTelL...
