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)