Logger.getLogger行为不一致,具体取决于变量是否内联

时间:2018-03-01 16:04:57

标签: java logging

稍后编辑: (为什么我认为它与here的情况相同)

所有操作都在一个实例方法中完成,in-out-out,每次我处理的每个文件。我提取的本地字段(而不是内联)在其他任何地方都没有使用,因此GC在迭代后无论如何都会清除它...

-

在标准的J2SE应用程序(从Eclipse运行main方法)中,使用 apache pdfbox pdf2dom 进行一些pdf到html的转换,我想要清除一些不需要的INFO日志条目。

意外 情况:

这段代码每次都能正常运行:

    Logger logger = Logger.getLogger("org.mabb.fontverter.opentype.TtfInstructions.TtfInstructionParser");
    logger.setLevel(Level.WARNING);

但是,如果我内联logger变量,它会开始出现意外行为:

Logger.getLogger("org.mabb.fontverter.opentype.TtfInstructions.TtfInstructionParser").setLevel(Level.WARNING);

在第二种情况下,记录器上的更改仅在允许通过一小段时间后生效:

  • 如果我调试并花费几秒钟检查线
  • 或者如果我处理多个pdf文件,意味着整个执行需要稍长时间......

对此有何解释?

谢谢。

1 个答案:

答案 0 :(得分:1)

简而言之,添加本地引用可以延长对象的生命周期。

来自Oracle的Vladimir Ivanov在OpenJDK core-libs邮件列表的[PATCH] Reduce Chance Of Mistakenly Early Backing Memory Cleanup中解释了这一点:

  

HotSpot中的JIT编译器积极地修剪dead locals,但他们确实如此   基于方法bytecode analysis(而不是优化的IR)。   因此,任何本地的使用都会延长其实时范围,即使是这种用法   在生成的代码中删除。这意味着当地居民的生活   超过其在生成的代码中的最后一次使用和所有安全点(在生成中)   代码)直到最后一次使用(在字节码级别上)将枚举它的本地   举行。

     

如果支持仅GC安全点,那么JIT仍然可以修剪   来自oop地图的未使用的本地人,但HotSpot没有他们和所有   生成的代码中的安全点保持完整的JVM状态,所以它总是如此   可以在其中任何一个上进行优化(然后进入代码   在生成的代码中删除了。)

     

如果在方法结束之前没有安全点,那么什么都不会   让对象保持活力。但是,因此,GC无法收集它   GC依靠安全点来标记线程堆栈。 (这就是我提到的原因   以前只有GC的安全点。)

因此,只要本地引用延长了logger对象的生命周期,使Logger.getLogger返回由本地var创建并保存的记录器,它就会全部工作。

对于日志记录,请勿使用方法本地引用。而是在wider scope中保留对记录器的引用,并在记录器开始发布记录之前优先设置一次。