You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@logging.apache.org by "Marat (Jira)" <ji...@apache.org> on 2023/03/24 20:30:00 UTC
[jira] [Updated] (LOG4J2-3657) Log4j memory leak via Classloader
[ https://issues.apache.org/jira/browse/LOG4J2-3657?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Marat updated LOG4J2-3657:
--------------------------
Summary: Log4j memory leak via Classloader (was: Log4j memory leak via multiple classloaders)
> 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
> Priority: Major
> 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.
> I think the issue is in the following lines, but I didn't try to fix it. I think you attach an object to the thread via the get method (because the field is defined like this:
> {code:java}
> ThreadLocal.withInitial(DefaultLogBuilder::new) {code}
> It means that you attach an object to a thread even _Constants.ENABLE_THREADLOCALS_ is disabled. My thoughts (but as I said I didn't check it):
> 1) Log4j code attaches _DefaultLogBuilder_ object to the thread
> 2) For creating _DefaultLogBuilder_ object -> DefaultLogBuilder class is used and linked to the object -> for loading the class _DefaultLogBuilder.class.getClassloader()_ is required and attached to the initial object
> 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 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}
>
> P.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)