Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak in Micrometer code when exceptions are returned from the method #5807

Open
adpaste opened this issue Nov 20, 2024 · 0 comments
Open

Comments

@adpaste
Copy link
Contributor

adpaste commented Nov 20, 2024

We've identified a memory leak in ThreadLocal when the application endpoint returns with an exception. E.g.:

@GET
@Path("/404")
public String notFound() {
    throw new NotFoundException("Not found");
}

It happens because in case of exceptions, the observation is started twice in:

case ON_EXCEPTION:
if (!isNotFoundException(event)) {
break;
}
startObservation(event);
break;

And:

This is an issue because Micrometer's SimpleObservationRegistry keeps the observation scope inside a ThreadLocal variable in SimpleObservationRegistry.java#L30:

private static final ThreadLocal<Observation.Scope> localObservationScope = new ThreadLocal<>();

The instance of Scope class contains a pointer to a previous scope SimpleObservation.java#L285:

static class SimpleScope implements Scope {
    @Nullable
    final Scope previousObservationScope;

And these 2 things are updated in SimpleObservation.java#L290-L291

this.previousObservationScope = registry.getCurrentObservationScope();
this.registry.setCurrentObservationScope(this);

Now, each request that ends with an exception causes this linked list of observations to grow, because the code in:

case FINISHED:
ObservationScopeAndContext finishedObservation = observations.remove(containerRequest);
if (finishedObservation != null) {
finishedObservation.jerseyContext.setRequestEvent(event);
Observation.Scope observationScope = finishedObservation.observationScope;
observationScope.close();
observationScope.getCurrentObservation().stop();
}
break;
is closing only one observation.

Here is an example test that reproduces the issue: 2.x...adpaste:jersey:memory_leak

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant