稍后编辑: (为什么我认为它与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);
在第二种情况下,记录器上的更改仅在允许通过一小段时间后生效:
对此有何解释?
谢谢。
答案 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中保留对记录器的引用,并在记录器开始发布记录之前优先设置一次。