में दृढ़ता से पहुंचने योग्य ऑब्जेक्ट पर कॉल किया गया है (हमने हाल ही में जावा 7 से जावा 8 तक हमारे संदेश प्रसंस्करण एप्लिकेशन को अपग्रेड किया है। अपग्रेड के बाद से, हमें कभी-कभी अपवाद मिलता है कि इसे पढ़ने के दौरान एक धारा बंद कर दी गई है। लॉगिंग से पता चलता है कि फाइनलज़र थ्रेड उस ऑब्जेक्ट पर finalize()
पर कॉल कर रहा है जिसमें स्ट्रीम है (जो बदले में स्ट्रीम बंद कर देता है)।जावा 8
कोड की बुनियादी रूपरेखा इस प्रकार है:
MIMEWriter writer = new MIMEWriter(out);
in = new InflaterInputStream(databaseBlobInputStream);
MIMEBodyPart attachmentPart = new MIMEBodyPart(in);
writer.writePart(attachmentPart);
MIMEWriter
और MIMEBodyPart
एक देसी माइम/HTTP पुस्तकालय का हिस्सा हैं। 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()
आउटपुटMIMEBodyPart.getContentStream()
jus पर सामग्री स्ट्रीम करने के लिए हमारी उपयोगिता विधिIOUtil.copy(getContentStream(), out)
पर कॉल करता है टी नियंत्रक में पारित इनपुट स्ट्रीम (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()
चल रहा है।
MIMEBodyPart
ऑब्जेक्ट वर्तमान थ्रेड के ढेर से this
MIMEBodyPart.writeBodyPartContent
के लिए स्टैक फ्रेम में निश्चित रूप से पहुंच योग्य है। मुझे समझ में नहीं आता कि क्यों JVM finalize()
पर कॉल करेगा।
मैंने प्रासंगिक कोड निकालने का प्रयास किया और इसे अपनी मशीन पर एक तंग लूप में चलाया, लेकिन मैं समस्या को पुन: उत्पन्न नहीं कर सकता। हम विश्वसनीय रूप से समस्या को हमारे देव सर्वरों में से एक पर उच्च लोड के साथ पुन: उत्पन्न कर सकते हैं, लेकिन एक छोटे प्रतिलिपि बनाने योग्य परीक्षण केस बनाने के किसी भी प्रयास में असफल रहा है। कोड जावा 7 के तहत संकलित किया गया है लेकिन जावा 8 के तहत निष्पादित करता है। अगर हम बिना किसी संकलन के जावा 7 पर वापस स्विच करते हैं, तो समस्या नहीं होती है।
कामकाज के रूप में, मैंने जावा मेल एमआईएम लाइब्रेरी का उपयोग करके प्रभावित कोड को फिर से लिखा है और समस्या दूर हो गई है (संभवतः जावा मेल finalize()
का उपयोग नहीं करता है)। हालांकि, मुझे चिंता है कि आवेदन में अन्य finalize()
विधियों को गलत तरीके से बुलाया जा सकता है, या जावा उन वस्तुओं को कचरा-संग्रह करने की कोशिश कर रहा है जो अभी भी उपयोग में हैं।
मुझे पता है कि वर्तमान सर्वोत्तम अभ्यास finalize()
का उपयोग करने के खिलाफ अनुशंसा करता है और मैं शायद finalize()
विधियों को हटाने के लिए इस घर से विकसित लाइब्रेरी पर फिर से विचार करूंगा। कहा जा रहा है, क्या कोई इस मुद्दे पर पहले आया है? क्या किसी के पास कारण के बारे में कोई विचार है?
मुझे आश्चर्य होगा अगर इसमें कोई अन्य स्पष्टीकरण नहीं है। मौजूदा धागे हमेशा संग्राहक के लिए लाइव ऑब्जेक्ट्स की पहचान करने के लिए "रूट" होता है। आप यह सुनिश्चित करने के लिए कैसे जानते हैं कि * आपके IOUtils.copy() रिटर्न से पहले * अंतिमकरण का आह्वान किया जा रहा है? – Bhaskar
यह एक जेआईटी बग की तरह लगता है। मैं जेआईटी डीबगिंग चालू कर दूंगा और देख सकता हूं कि वहां कोई पैटर्न है या नहीं। – chrylis
@ भास्कर, अपवाद साबित करता है कि स्ट्रीम बंद है जबकि 'IOUtil.copy()' निष्पादित हो रहा है। – Nathan