Java Log4j2自定义Hibernate Appender内存泄漏

Java Log4j2自定义Hibernate Appender内存泄漏,java,memory-leaks,log4j2,Java,Memory Leaks,Log4j2,我们将应用程序从一个自己的小日志组件移动到了Log4j2。 在我们最大的安装中,该应用程序每天运行约60000个作业 我们编写自己的Appender,它使用Hibernate将数据写入数据库(请参阅InnovaintegrationPortalHibernateAppender) 运行约36小时后,JVM因内存不足异常/错误(OOME)而崩溃,分析hprof时,我发现org.apache.logging.log4j.core.appender.AbstractManager类的容量为763,5M

我们将应用程序从一个自己的小日志组件移动到了Log4j2。 在我们最大的安装中,该应用程序每天运行约60000个作业

我们编写自己的Appender,它使用Hibernate将数据写入数据库(请参阅InnovaintegrationPortalHibernateAppender)

运行约36小时后,JVM因内存不足异常/错误(OOME)而崩溃,分析hprof时,我发现org.apache.logging.log4j.core.appender.AbstractManager类的容量为763,5MB

见所附分析截图(2019-04-12 13_20_45-eclips…)

更深入地说,我试图在一个测试类中重建行为,并分析其结果(见截图1)

我觉得好像是内存泄漏

Innovai集成便携式光纤交换机

package de.itout.innova.log4j.innova_log4j_appender;
导入de.itout.innova.ssp.entities.ssp.entities.*;
导入de.itout.jpa.util.*;
导入java.io.*;
导入java.util.*;
导入javax.persistence.*;
导入org.apache.logging.log4j.core.*;
导入org.apache.logging.log4j.core.appender.*;
导入org.apache.logging.log4j.core.config.plugins.*;
导入org.apache.logging.log4j.core.layout.*;
/**
*
*@作者斯文德曼
*/
@插件(name=“innovaintegrationportalhibernateappender”,category=“Core”,elementType=“appender”)
公共类InnovaIntegrationPortalHibernateAppender扩展了AbstractAppender
{
私用线绳;
私有字符串版本;
私有字符串laufId;
私人实体管理者;

public InnovaIntegrationPortalHibernateAppender(字符串名称、筛选器、布局)Hibernate可能会将对象保留在其缓存中。请在提交后立即尝试退出对象。

我认为这就是正在发生的事情:

private static final LoggerContext ctx ...

Configuration config = ctx.getConfiguration();

config.addAppender(fullAppender);
您从未删除它,所以它一直添加到静态字段中。您可以调试并查看Log4j2中的内容。我还没有调试

内存泄漏通常来自静态字段和类加载器


最好的选择是不使用jdbc进行日志记录。它的设计目的是以另一种方式工作,而不是动态添加/删除附加器,因为您必须执行对象的所有缩放操作。您可能更容易创建外观模式并隐藏其中的复杂性,并且只公开两种写入DB的方法。

Hibernate/JPA to w将一行写入表?这太过分了。我会使用一个简单的JDBC连接(如果您是Spring用户,也可以使用JdbcTemplate)来实现这一点。我希望看到汇集的JDBC连接。您这样做很复杂。@duffymo感谢您的澄清。最初的问题是,我在系统中得到了大约200个不同版本的作业。所有作业都有两个日志级别的参数:Logelevel文件和Loglevel DB。因此,现在的目标是通过该作业以编程方式生成日志记录器id引用jdbc appender,在ref中是Loglevel DB。第二个目标是通过编程生成一个文件appender,我可以从日志级别文件的同一个记录器中引用它。感谢您的建议。我在提交后添加了一个
em.clear()
,但仍然没有更改。此外,我认为
em.close()
已经关闭em,引用到em的所有对象都可以是gc。我不记得Hibernate的详细信息-默认情况下它有二级缓存吗?或者你可以为应用或实体启用它?确保日志记录没有添加到二级缓存。我的意思是“你可以启用它”tbh离开propper日志框架不是一种合理的方法。当您在Task类的代码中进一步深入时,追加器将被删除,但仍保留在对象中。
loggerConfig.removeAppender(laufId+“_文件”);config.getLoggerConfig(laufId)。removeAppender(laufId+“_文件”);config.removeLogger(laufId);config.getRootLogger().removeAppender(laufId+“_FILE”);ctx.UpdateLogger();ThreadContext.clearAll();
我更新了测试场景,将ctx设置为非静态/最终字段,并使用
synchronized
getter访问它,但该对象仍然填充了appender并炸毁了jvm。