[ https://issues.apache.org/jira/browse/LOG4J2-3657?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17704818#comment-17704818 ]
Volkan Yazici commented on LOG4J2-3657: --------------------------------------- Thanks so much for the report, through investigation, and the fix [~mkamalov]! (y) I have pushed the fix to {{{}2.x{}}}. You can follow the status of the build [here|https://github.com/apache/logging-log4j2/actions/runs/4515421697]. Would you mind confirming that the published SNAPSHOT artifacts fixes the issue, and if so, close the issue, please? Let me remind that we have [started using GitHub Issues officially|https://logging.apache.org/log4j/2.x/support.html]. Given the amount of effort you have already put into this, a GitHub pull request would be great next time! ;) > Log4j memory leak via Classloader > --------------------------------- > > Key: LOG4J2-3657 > URL: https://issues.apache.org/jira/browse/LOG4J2-3657 > Project: Log4j 2 > Issue Type: Bug > Components: API > Affects Versions: 2.20.0 > Reporter: Marat Kamalov > Assignee: Volkan Yazici > Priority: Critical > Attachments: image-2023-03-24-21-05-55-700.png, > image-2023-03-24-21-07-04-937.png > > > We have a memory leak in the application. If we stop and run Jetty in the > loop in JUnit we get OOM. > The issue is in the following lines. I think Log4j attaches an object to the > thread via the _get_ method (because the field is defined like this: > {code:java} > private static final ThreadLocal<DefaultLogBuilder> logBuilder = > ThreadLocal.withInitial(DefaultLogBuilder::new);{code} > It means that Log4j attaches an object to a thread {*}even > _Constants.ENABLE_THREADLOCALS_ is disabled{*}. My thoughts: > 1) Log4j code attaches _DefaultLogBuilder_ object to threads > 2) _DefaultLogBuilder_ object has a link to _DefaultLogBuilder.class_ that > has a link to _DefaultLogBuilder.class.getClassloader()_ > 3) _DefaultLogBuilder.class.getClassloader()_ is a Web App Classloader and > during our JUnit testing many classes are loaded to the classloader > 4) I suspect somewhere some Thread Pool is used and even if we clean all > resources in the application, Log4j *holds classloaders and all loaded > classes* via _DefaultLogBuilder.class.getClassloader()_ > > I suggest checking _Constants.ENABLE_THREADLOCALS_ variable before calling > _logBuilder.get()_ in _org.apache.logging.log4j.spi.AbstractLogger._ *After > the following changes, the problem is gone.* (except additionally I added > {_}log4j2.disable.jmx=true{_}, because it has a similar issue, but I think it > is not a log4j issue) > {code:java} > /** > * Returns a log builder that logs at the specified level. > * > * @since 2.20.0 > */ > protected LogBuilder getLogBuilder(Level level) { > if (Constants.ENABLE_THREADLOCALS) { > DefaultLogBuilder builder = logBuilder.get(); > if (!builder.isInUse()) { > return builder.reset(this, level); > } > } > return new DefaultLogBuilder(this, level); > } {code} > Original code: > {code:java} > /** > * Returns a log builder that logs at the specified level. > * > * @since 2.20.0 > */ > protected LogBuilder getLogBuilder(Level level) { > DefaultLogBuilder builder = logBuilder.get(); > return Constants.ENABLE_THREADLOCALS && !builder.isInUse() ? > builder.reset(this, level) > : new DefaultLogBuilder(this, level); > } {code} > P.S. Please, if it is possible can you include the fix in an upcoming > release, the issue randomly happens during our application build and it is a > headache for us :) Thank you. > P.S.S. We use a free license of Yourkit for open-source projects. Please, > look at the picture from a profiler. > !image-2023-03-24-21-05-55-700.png! -- This message was sent by Atlassian Jira (v8.20.10#820010)