finalize() 在 Java 8 中调用强可访问的对象
我们最近将消息处理应用程序从 Java 7 升级到 Java 8。自升级以来,我们偶尔会遇到一个异常,即在读取流时已关闭流。日志记录显示终结器线程正在调用保存流的对象(这反过来又关闭流)。finalize()
代码的基本大纲如下:
MIMEWriter writer = new MIMEWriter( out );
in = new InflaterInputStream( databaseBlobInputStream );
MIMEBodyPart attachmentPart = new MIMEBodyPart( in );
writer.writePart( attachmentPart );
MIMEWriter
并且是自家开发的MIME / HTTP库的一部分。 扩展 ,它具有以下各项:MIMEBodyPart
MIMEBodyPart
HTTPMessage
public void close() throws IOException
{
if ( m_stream != null )
{
m_stream.close();
}
}
protected void finalize()
{
try
{
close();
}
catch ( final Exception ignored ) { }
}
异常发生在 的调用链中,如下所示:MIMEWriter.writePart
-
MIMEWriter.writePart()
写入部件的标头,然后调用part.writeBodyPartContent( this )
-
MIMEBodyPart.writeBodyPartContent()
调用我们的实用程序方法将内容流式传输到输出IOUtil.copy( getContentStream(), out )
-
MIMEBodyPart.getContentStream()
只是返回传递到 contstructor 中的输入流(请参阅上面的代码块) -
IOUtil.copy
具有一个循环,该循环从输入流读取 8K 块并将其写入输出流,直到输入流为空。
在 运行时调用 ,并得到以下异常:MIMEBodyPart.finalize()
IOUtil.copy
java.io.IOException: Stream closed
at java.util.zip.InflaterInputStream.ensureOpen(InflaterInputStream.java:67)
at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:142)
at java.io.FilterInputStream.read(FilterInputStream.java:107)
at com.blah.util.IOUtil.copy(IOUtil.java:153)
at com.blah.core.net.MIMEBodyPart.writeBodyPartContent(MIMEBodyPart.java:75)
at com.blah.core.net.MIMEWriter.writePart(MIMEWriter.java:65)
我们在记录调用方堆栈跟踪的方法中放置了一些日志记录,并证明它肯定是在运行时调用的终结器线程。HTTPMessage.close()
HTTPMessage.finalize()
IOUtil.copy()
该对象绝对可以从当前线程的堆栈访问,就像 在 的堆栈帧中一样。我不明白为什么JVM会调用.MIMEBodyPart
this
MIMEBodyPart.writeBodyPartContent
finalize()
我尝试提取相关代码并在我自己的计算机上以紧密循环运行它,但我无法重现问题。我们可以在其中一个开发服务器上可靠地重现高负载问题,但任何创建较小的可重现测试用例的尝试都失败了。代码在 Java 7 下编译,但在 Java 8 下执行。如果我们在不重新编译的情况下切换回Java 7,则不会出现问题。
作为一种解决方法,我使用Java Mail MIME库重写了受影响的代码,并且问题已经消失(可能是Java Mail不使用)。但是,我担心应用程序中的其他方法可能被错误地调用,或者Java正在尝试对仍在使用的对象进行垃圾回收。finalize()
finalize()
我知道当前的最佳实践建议不要使用,我可能会重新访问这个自成的库来删除这些方法。话虽如此,以前有人遇到过这个问题吗?有没有人对原因有任何想法?finalize()
finalize()