我正在调查java进程中发生的突然内存提升。我看到堆大小一直增长到3-4GB。经过调查,我发现在一个类中,日志记录正在发生(这是非常频繁的,比如每1或2毫秒),它在1秒内产生大约4mb的日志。所以据我所知,这是堆大小增加的原因。此外,在代码从类中出来并且日志记录停止之后,堆大小不会减小。这个过程使用log4j-1.2.16.jar。
我有以下问题。
log4j是否因为频繁的日志记录而在堆上创建了太多的对象?如果是,是预期的行为还是log4j中的某些限制在log4j2中得到了解决?
为什么堆大小没有减小?log4j是否持有对堆上对象的引用,因为gc没有收集这些对象?
请帮助我理解log4j和jvm的这种行为。我不知道这是否是已知的事情,log4j2已经解决了。
1条答案
按热度按时间rur96b6h1#
log4j被标记为生命周期的结束,所以升级到更新的版本是个好主意。编写大量日志文件可能会导致性能问题,具体取决于您如何使用日志api,但是您应该仍然能够在不升级的情况下解决一些日志问题。
查看消息并检查详细程度。一个关键问题是打印太多的消息或代码,这些消息或代码不需要检查日志记录级别,因为即使不需要消息,也会计算字符串表达式。这可能是内存分配过高和不必要的原因。考虑:
如果将日志记录级别更改为
WARN
,则仍会执行消息的上述字符串串联,如果value.toString()
这是一个昂贵的内存操作,除了jvm添加的stringbuilder调用之外,还会有更多不必要的对象分配。更改log4j调用以在登录前检查级别:使用log4j2,您可以使用格式字符串或
Supplier<String>
只有在需要日志消息时,才会计算日志消息的字符串连接。写入system.out可能会很昂贵,因此请确保控制台中只显示信息消息,并使用附加器,以便调试消息转到日志文件。