यदि मैं प्रतिक्रिया को बंद नहीं करता तो क्या हो सकता है।


98

गो में, मेरे पास कुछ http प्रतिक्रियाएं हैं और मैं कभी-कभी कॉल करना भूल जाता हूं:

resp.Body.Close()

इस मामले में क्या होता है? स्मृति रिसाव होगा? defer resp.Body.Close()प्रतिक्रिया वस्तु मिलने के तुरंत बाद क्या यह सुरक्षित है ?

client := http.DefaultClient
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
    return nil, err
}

क्या यदि कोई त्रुटि होती है, कर सकता है respया resp.Bodyनहीं के बराबर हो सकता है?


इसके लिए defer resp.Body.Close () के बाद इरेट करना ठीक है! = Nil जब रिटर्न मौजूद है, क्योंकि जब इरिल nil नहीं है, तो यह पहले से ही बंद है। दूसरी ओर अनुरोध के सफल होने पर शरीर को स्पष्ट रूप से बंद करने की आवश्यकता होती है।
वसंत गणेश के

जवाबों:


110

इस मामले में क्या होता है? क्या मेमोरी लीक होगी?

यह रिसोर्स लीक है। कनेक्शन का फिर से उपयोग नहीं किया जाएगा, और उस स्थिति में खुला रह सकता है जिस स्थिति में फ़ाइल विवरणक को मुक्त नहीं किया जाएगा।

प्रतिक्रिया ऑब्जेक्ट मिलने के तुरंत बाद defer resp.Body.Close () में रखना सुरक्षित है?

नहीं, प्रलेखन में दिए गए उदाहरण का पालन करें और त्रुटि की जांच करने के तुरंत बाद इसे बंद कर दें।

client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
    return nil, err
}
defer resp.Body.Close()

से http.Clientप्रलेखन:

यदि दी गई त्रुटि शून्य है, तो प्रतिक्रिया में एक गैर-शून्य निकाय होगा जिसे उपयोगकर्ता को बंद करने की उम्मीद है। यदि बॉडी ईओएफ और बंद दोनों के लिए नहीं पढ़ी जाती है, तो क्लाइंट का अंतर्निहित राउंडटाइपर (आमतौर पर ट्रांसपोर्ट) बाद के "रखने के लिए" अनुरोध के लिए सर्वर पर लगातार टीसीपी कनेक्शन का फिर से उपयोग करने में सक्षम नहीं हो सकता है।


4
इस लिंक के अनुसार आपके कोड के साथ कनेक्शन को लीक करना अभी भी संभव है। कुछ उदाहरण हैं जहां प्रतिक्रिया गैर-शून्य है और त्रुटि गैर-शून्य है।
mmcdole

13
@mmcdole: यह पोस्ट सिर्फ गलत है, और इसमें कोई गारंटी नहीं है कि यह घबराएगा नहीं, क्योंकि किसी त्रुटि पर जो भी प्रतिक्रिया दी जाती है, उसमें परिभाषित राज्य नहीं होता है। यदि किसी त्रुटि पर एक निकाय बंद नहीं हुआ है, तो यह बग है और रिपोर्ट करने की आवश्यकता है। आपको आधिकारिक क्लाइंट प्रलेखन द्वारा जाना चाहिए , जिसमें कहा गया है कि "एक त्रुटि पर, किसी भी प्रतिक्रिया को अनदेखा किया जा सकता है", बजाय एक यादृच्छिक ब्लॉग पोस्ट के।
जिमब

2
@ डेल-बॉय: यदि आप उस ग्राहक से अधिक अनुरोध करने की अपेक्षा करते हैं, तो आपको शरीर को पढ़ने का प्रयास करना चाहिए ताकि कनेक्शन का पुन: उपयोग किया जा सके। यदि आपको कनेक्शन की आवश्यकता नहीं है, तो शरीर को पढ़ने में परेशान न करें। यदि आप शरीर को पढ़ते हैं, तो इसे लपेटें io.LimitReader। मैं आमतौर पर एक काफी छोटी सीमा का उपयोग करता हूं, क्योंकि यह नया कनेक्शन बनाने के लिए तेज़ है यदि अनुरोध बहुत बड़ा है।
जिमब

1
यह इंगित करने योग्य है कि _, err := client.Do(req)फ़ाइल डिस्क्रिप्टर के खुले रहने पर भी परिणाम मिलता है। तो भले ही किसी को परवाह नहीं है कि प्रतिक्रिया क्या है, फिर भी इसे एक चर पर असाइन करना और शरीर को बंद करना आवश्यक है।
23

1
रुचि रखने वाले किसी भी व्यक्ति के लिए, पूर्ण प्रलेखन है (जोर दिया गया): "त्रुटि पर, किसी भी प्रतिक्रिया को नजरअंदाज किया जा सकता है। गैर-शून्य प्रतिक्रिया के साथ एक गैर-शून्य प्रतिक्रिया केवल तब होती है जब CheckRedirect विफल रहता है, और तब भी वापस किया गया प्रतिक्रिया .Body पहले से ही है। बन्द है।"
निशाण्थनममुघम

15

यदि fd से जुड़े संसाधनों की तुलना में विधि के Response.Bodyसाथ बंद Close()नहीं किया जाएगा, तो उसे मुक्त नहीं किया जाएगा। यह रिसोर्स लीक है।

समापन Response.Body

से प्रतिक्रिया स्रोत :

बॉडी को बंद करना कॉलर की जिम्मेदारी है।

इसलिए ऑब्जेक्ट के लिए कोई फाइनल नहीं है और इसे स्पष्ट रूप से बंद किया जाना चाहिए।

हैंडलिंग और स्थगित क्लीनअप में त्रुटि

त्रुटि पर, किसी भी प्रतिक्रिया को अनदेखा किया जा सकता है। एक गैर-शून्य प्रतिक्रिया के साथ एक गैर-शून्य त्रुटि केवल तब होती है जब CheckRedirect विफल रहता है, और तब भी वापस किया गया Resp.Body पहले से ही बंद है।

resp, err := http.Get("http://example.com/")
if err != nil {
    // Handle error if error is non-nil
}
defer resp.Body.Close() // Close body only if response non-nil

4
आपको ध्यान देना चाहिए कि उन्हें आपकी त्रुटि से निपटने की स्थिति में वापस आना चाहिए। यदि उपयोगकर्ता अपनी त्रुटि हैंडलिंग में वापस नहीं आता है, तो यह आतंक का कारण बनने वाला है।
सेबवुड

3

पहले विवरणक कभी बंद नहीं होता है, जैसा कि ऊपर उल्लेखित चीजें हैं।

और क्या अधिक persistConnहै, अगर DisableKeepAlivesयह गलत है , तो गोलैंग कनेक्शन ( रैप करने के लिए संरचना का उपयोग करके ) को कैश करेगा ।

उपयोग client.Doविधि के बाद गोलंग में , गो readLoopएक चरण के रूप में गोरोइन विधि चलाएगा ।

इसलिए golang http में transport.go, तब तक चैनल pconn(persistConn struct)में नहीं डाला जाएगा idleConnजब तक कि readLoopविधि में रेक रद्द नहीं हो जाता है , और readLoopजब तक रेक रद्द नहीं हो जाता है तब तक यह गोरोइन ( विधि) अवरुद्ध हो जाएगा।

यहाँ यह कोड दिखाया गया है।

यदि आप अधिक जानना चाहते हैं, तो आपको readLoopविधि देखने की आवश्यकता है ।


1

Https://golang.org/src/net/http/client.go देखें
"जब गलती शून्य होती है, तो सम्मान में हमेशा गैर-शून्य सम्मान होता है। बॉडी।"

लेकिन वे कहते हैं कि जब गलत नहीं है! = nil, सम्मान हमेशा शून्य होता है। वे कहते हैं:
"यदि resp.Body बंद नहीं है, तो क्लाइंट का अंतर्निहित राउंडटाइपर (आमतौर पर परिवहन) बाद में" रखने के लिए जीवित "अनुरोध के लिए सर्वर पर लगातार टीसीपी कनेक्शन का उपयोग करने में सक्षम नहीं हो सकता है।"

इसलिए मैंने आम तौर पर इस तरह की समस्या को हल किया है:

client := http.DefaultClient
resp, err := client.Do(req)
if resp != nil {
   defer resp.Body.Close()
}
if err != nil {
    return nil, err 
}

3
यह गलत है, और कोई गारंटी नहीं है कि जब कोई त्रुटि होती है, तो resp.Body नट नील है।
जिमब

1
धन्यवाद @JimB डॉक्स में शब्दांकन "त्रुटि पर, किसी भी प्रतिक्रिया को अनदेखा किया जा सकता है।" यह कहना अधिक सटीक होगा कि "त्रुटि पर, प्रतिक्रिया बॉडी हमेशा बंद रहती है।"
कैंडिता

1
नहीं, क्योंकि आमतौर पर एक प्रतिक्रिया निकाय को बंद नहीं किया जाना है। यदि आप डॉक्स में उस पैराग्राफ को पढ़ना जारी रखते हैं - "नॉन-निल रिस्पॉन्स के साथ नॉन-निल त्रुटि केवल तब होती है जब चेकरेडायरेक्ट विफल हो जाता है, और तब भी रिस्पॉन्स.बॉडी पहले से ही बंद है।"
जिमब जूल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.