System.gc () को कॉल करना बुरा क्यों है?


326

जावा में व्यक्ति को मुफ्त में बल देने के तरीके के बारे में एक प्रश्न का उत्तर देने के बाद (लड़का 1.5GB हैशपॉप को साफ कर रहा था ) , मुझे बताया गया कि इसे मैन्युअल रूप से कॉल करने के लिए बुरा व्यवहार है , लेकिन टिप्पणियां पूरी तरह से आश्वस्त नहीं थीं। इसके अलावा, किसी को भी उकसाने की हिम्मत नहीं हुई, और न ही मेरे जवाब को खारिज किया।System.gc()System.gc()

मुझे वहां बताया गया था कि यह बुरा अभ्यास है, लेकिन तब मुझे यह भी बताया गया था कि कचरा संग्रहकर्ता व्यवस्थित रूप से दुनिया को अब नहीं रोकता है, और यह भी कि यह प्रभावी रूप से केवल एक संकेत के रूप में जेवीएम द्वारा उपयोग किया जा सकता है, इसलिए मैं इस तरह का हूं नुकसान पर।

मैं समझता हूं कि जेवीएम आमतौर पर आपसे बेहतर जानता है जब उसे स्मृति को पुनः प्राप्त करने की आवश्यकता होती है। मैं यह भी समझता हूं कि कुछ किलोबाइट के बारे में चिंता करना मूर्खतापूर्ण है। मुझे यह भी समझ में आता है कि कुछ वर्षों पहले तक मेगाबाइट का डेटा वैसा नहीं था। लेकिन फिर भी, 1.5 गीगाबाइट्स? और आप जानते हैं कि स्मृति में चारों ओर 1.5 जीबी डेटा लटका हुआ है; ऐसा नहीं है कि यह अंधेरे में एक शॉट है। है System.gc()व्यवस्थित बुरा, या वहाँ कुछ बिंदु है जिस पर यह ठीक हो जाता है?

तो सवाल वास्तव में दोहरा है:

  • कॉल करना क्यों बुरा है या नहीं System.gc()? क्या यह वास्तव में कुछ कार्यान्वयनों के तहत जेवीएम के लिए केवल एक संकेत है, या यह हमेशा एक पूर्ण संग्रह चक्र है? क्या वास्तव में कचरा कलेक्टर कार्यान्वयन हैं जो दुनिया को रोके बिना अपना काम कर सकते हैं? कृपया मेरे उत्तर की टिप्पणियों में लोगों द्वारा किए गए विभिन्न कथनों पर कुछ प्रकाश डालें ।
  • दहलीज कहां है? क्या यह कभी भी कॉल करने के लिए एक अच्छा विचार नहीं है System.gc(), या क्या यह स्वीकार्य है? यदि हां, तो वे समय क्या हैं?

4
मुझे लगता है कि System.gc () को कॉल करने का एक अच्छा समय है जब आप कुछ ऐसा कर रहे हैं जो पहले से ही लंबी लोडिंग प्रक्रिया है। उदाहरण के लिए, मैं एक गेम पर काम कर रहा हूं और लोडिंग प्रक्रिया के अंत में गेम को एक नए स्तर पर लोड करने पर System.gc () कॉल करने की योजना बना रहा हूं। उपयोगकर्ता पहले से ही थोड़ा इंतजार कर रहा है, और अतिरिक्त प्रदर्शन में वृद्धि इसके लायक हो सकती है; लेकिन मैं इस व्यवहार को अक्षम करने के लिए कॉन्फ़िगरेशन स्क्रीन में एक विकल्प भी रखूंगा।
10:58

41
Bozho: प्रश्न के पहले शब्द पर ध्यान दें। इसे कॉल न करना सबसे अच्छा अभ्यास क्यों है? बस एक मंत्र को दोहराते हुए एक शापित चीज़ की व्याख्या नहीं करता है।
JUST MY सही ओपिनियन

1
एक और मामला java-monitor.com/forum/showthread.php?t=188 में समझाया गया है, जहां यह बताता है कि कैसे System.gc ()
Shirishkumar Bari

जवाबों:


243

हर कोई हमेशा बचने के लिए कहता System.gc()है कि यह मौलिक रूप से टूटे हुए कोड का एक बहुत अच्छा संकेतक है । कोई भी कोड जो शुद्धता के लिए उस पर निर्भर करता है निश्चित रूप से टूट गया है; कोई भी जो प्रदर्शन के लिए उस पर भरोसा करता है वह सबसे अधिक टूट जाता है।

आप नहीं जानते कि आप किस प्रकार का कचरा संग्रहकर्ता चला रहे हैं। निश्चित रूप से कुछ ऐसे हैं जो आपके अनुसार "दुनिया को रोक नहीं " करते हैं, लेकिन कुछ JVM उस स्मार्ट या विभिन्न कारणों से नहीं हैं (शायद वे एक फोन पर हैं?) ऐसा नहीं करते हैं। आप नहीं जानते कि यह क्या करने जा रहा है।

इसके अलावा, यह कुछ भी करने की गारंटी नहीं है। JVM आपके अनुरोध को पूरी तरह से अनदेखा कर सकता है।

"आपको नहीं पता कि यह क्या करेगा," "आप नहीं जानते कि क्या यह मदद भी करेगा," और "आपको इसे वैसे भी कॉल करने की आवश्यकता नहीं होनी चाहिए", लोग आमतौर पर यह कहने में इतने मजबूर क्यों हैं आपको इसे कॉल नहीं करना चाहिए। मुझे लगता है कि यह "अगर आपको यह पूछने की आवश्यकता है कि क्या आपको इसका उपयोग करना चाहिए, तो आपको ऐसा नहीं करना चाहिए"


EDIT दूसरे धागे से कुछ चिंताओं को दूर करने के लिए:

आपके द्वारा लिंक किए गए धागे को पढ़ने के बाद, कुछ और चीजें हैं जो मैं इंगित करना चाहता हूं। सबसे पहले, किसी ने सुझाव दिया कि कॉलिंग gc()मेमोरी को सिस्टम में वापस ला सकती है। यह निश्चित रूप से सच नहीं है - जावा हीप जावा आवंटन से स्वतंत्र रूप से बढ़ता है।

जैसा कि, जेवीएम मेमोरी (कई दसियों मेगाबाइट) का आयोजन करेगा और आवश्यक रूप से ढेर बढ़ाएगा। यह आवश्यक नहीं है कि आप जावा की वस्तुओं को मुक्त करते समय भी उस मेमोरी को सिस्टम में वापस लाएँ; यह भविष्य के जावा आवंटन के लिए उपयोग की जाने वाली आवंटित मेमोरी पर पकड़ के लिए पूरी तरह से स्वतंत्र है।

यह दिखाने के लिए कि यह संभव है जो System.gc()कुछ भी नहीं करता है, देखें:

http://bugs.sun.com/view_bug.do?bug_id=6668279

और विशेष रूप से इसमें -XX है: DisableExplicitGC VM विकल्प।


1
आप कुछ अजीब रब गोल्डबर्ग-एस्क सेटअप का निर्माण करने में सक्षम हो सकते हैं, जहां जीसी चलाया जाता है वह विधि आपके कोड की शुद्धता को प्रभावित करती है। शायद यह कुछ अजीब थ्रेडिंग इंटरैक्शन को मास्क कर रहा है, या हो सकता है कि प्रोग्राम के चलने पर एक अंतिम प्रभाव हो। मुझे पूरा यकीन नहीं है कि यह संभव है लेकिन यह हो सकता है, इसलिए मुझे लगा कि मैं इसका उल्लेख करूंगा।
स्टीवन श्लैंस्कर

2
@zneak उदाहरण के लिए आपने फाइनल कोड में महत्वपूर्ण कोड डाल दिया है (जो कि मौलिक रूप से टूटा हुआ कोड है)
मार्टिन

3
मैं जोड़ना चाहूंगा कि कुछ कोने मामले हैं जहां System.gc()उपयोगी है और यहां तक ​​कि आवश्यक भी हो सकता है। उदाहरण के लिए विंडोज़ पर UI एप्लिकेशन में यह विंडो को कम करने से पहले विंडो की रिस्टोरिंग-प्रोसेस को बहुत तेज कर सकता है। इससे पहले कि आप विंडो को कम से कम करें (विशेषकर तब जब यह कुछ समय के लिए कम से कम रहे और प्रक्रिया के कुछ हिस्सों की अदला-बदली हो जाए। डिस्क)।
जोकिम सॉर

2
@AndrewJanke मैं ऐसा कोड कहूंगा जो उन WeakReferenceवस्तुओं के लिए उपयोग करता है जिन्हें आप पकड़ना चाहते हैं, प्रारंभ से ही गलत है, कचरा संग्रह या नहीं। आपके पास std::weak_ptrC ++ संस्करण में एक ही समस्या होगी (हालाँकि आप C ++ संस्करण में इस समस्या को पहले ही नोटिस कर सकते हैं क्योंकि आप जावा संस्करण में हैं क्योंकि ऑब्जेक्ट विनाश को अंतिम रूप नहीं दिया जाएगा)।
JAB

2
@rebeccah यह एक बग है, इसलिए हां, मैं इसे 'निश्चित रूप से टूट गया' कहूंगा। तथ्य System.gc()यह है कि इसे ठीक करता है एक अच्छा तरीका है, अच्छा कोडिंग अभ्यास नहीं।
स्टीवन श्लैंस्कर

149

यह पहले ही समझाया जा चुका है कि कॉलिंग कुछ भी नहीं system.gc() कर सकती है, और यह कि किसी भी कोड को चलाने के लिए "संग्राहक" की जरूरत है, टूट गया है।

हालांकि, व्यावहारिक कारण यह System.gc()है कि कॉल करने के लिए बुरा अभ्यास है कि यह अक्षम है। और सबसे खराब स्थिति में, यह बहुत ही अयोग्य है ! मुझे समझाने दो।

एक विशिष्ट GC एल्गोरिथ्म ढेर में सभी गैर-कचरा वस्तुओं को ट्रेस करके कचरा की पहचान करता है, और यह उल्लेख करते हुए कि किसी भी वस्तु का दौरा नहीं किया जाना चाहिए कचरा। इसमें से, हम कचरा संग्रहण के कुल कार्य को मॉडल कर सकते हैं जिसमें एक भाग होता है जो लाइव डेटा की मात्रा के लिए आनुपातिक होता है, और दूसरा भाग जो कचरे की मात्रा के लिए आनुपातिक होता है; यानी work = (live * W1 + garbage * W2)

अब मान लें कि आप एक एकल-थ्रेडेड अनुप्रयोग में निम्नलिखित करते हैं।

System.gc(); System.gc();

पहली कॉल विल (हम भविष्यवाणी करते हैं) (live * W1 + garbage * W2)काम करते हैं, और बकाया कचरे से छुटकारा पा लेते हैं।

दूसरी कॉल (live* W1 + 0 * W2)काम करेगी और कुछ भी नहीं लौटाएगी। दूसरे शब्दों में, हमने (live * W1)काम किया है और पूरी तरह से कुछ भी हासिल नहीं किया है

हम कूड़े की एक इकाई को इकट्ठा करने के लिए आवश्यक कार्य की मात्रा के रूप में कलेक्टर की दक्षता को मॉडल कर सकते हैं; यानी efficiency = (live * W1 + garbage * W2) / garbage। इसलिए जीसी को यथासंभव कुशल बनाने के लिए, जब हम जीसी चलाते हैं, तो हमें मूल्य को अधिकतम करना होगा garbage; यानी ढेर होने तक इंतजार करें। (और भी, ढेर को जितना संभव हो उतना बड़ा करें। लेकिन यह एक अलग विषय है।)

यदि एप्लिकेशन हस्तक्षेप नहीं करता है (कॉल करके System.gc()), जीसी तब तक इंतजार करेगा जब तक कि चलने से पहले ढेर पूरा नहीं हो जाता है, जिसके परिणामस्वरूप कचरा 1 का कुशल संग्रह होता है । लेकिन अगर आवेदन जीसी को चलाने के लिए मजबूर करता है, तो संभावना है कि ढेर भरा नहीं होगा, और इसका परिणाम यह होगा कि कचरा अक्षम रूप से एकत्र किया जाता है। और जितनी अधिक बार आवेदन जीसी को मजबूर करता है, उतना अधिक अक्षम जीसी बन जाता है।

नोट: उपरोक्त स्पष्टीकरण इस तथ्य पर चमकता है कि एक विशिष्ट आधुनिक जीसी विभाजन को "रिक्त स्थान" में बदल देता है, जीसी गतिशील रूप से ढेर का विस्तार कर सकता है, गैर-कचरा वस्तुओं के अनुप्रयोग का कार्य सेट भिन्न हो सकता है और इसी तरह। फिर भी, एक ही मूल प्राचार्य बोर्ड के सभी सच्चे कचरा कलेक्टरों 2 पर लागू होता है । जीसी को चलाने के लिए मजबूर करना अक्षम है।


1 - यह "थ्रूपुट" कलेक्टर कैसे काम करता है। कचरा उठाने वाले को कब शुरू करना है, यह तय करने के लिए सीएमएस और जी 1 जैसे समवर्ती कलेक्टर विभिन्न मानदंडों का उपयोग करते हैं।

2 - मैं उन मेमोरी मैनेजरों को भी शामिल कर रहा हूं जो विशेष रूप से संदर्भ गिनती का उपयोग करते हैं, लेकिन कोई भी जावा कार्यान्वयन उस दृष्टिकोण का उपयोग नहीं करता है ... अच्छे कारण के लिए।


45
+1 अच्छी व्याख्या। ध्यान दें कि यह तर्क केवल तभी लागू होता है जब आप थ्रूपुट की परवाह करते हैं। यदि आप विशिष्ट बिंदुओं पर अव्यक्तता का अनुकूलन करना चाहते हैं, तो मजबूर जीसी समझ में आ सकता है। एक खेल में (काल्पनिक रूप से बोलना) आप स्तरों के दौरान देरी से बचना चाह सकते हैं, लेकिन आप स्तर लोड के दौरान देरी के बारे में परवाह नहीं करते हैं। तब यह समझ में आता है कि स्तर लोड के बाद GC को मजबूर करना है। यह समग्र थ्रूपुट में कमी करता है, लेकिन यह वह नहीं है जो आप अनुकूलन कर रहे हैं।
सेल्के

2
@ सालेस्के - जो आप कहते हैं वह सच है। हालाँकि, स्तरों के बीच GC चलाना एक बैंड-सहायता समाधान है ... और विलंबता समस्या को हल नहीं करता है यदि स्तर लंबे समय तक ले जाते हैं जो आपको वैसे भी एक स्तर के दौरान GC चलाने की आवश्यकता है। एक बेहतर दृष्टिकोण एक समवर्ती (कम ठहराव) कचरा कलेक्टर का उपयोग करना है ... यदि मंच इसका समर्थन करता है।
स्टीफन सी

पूरी तरह से निश्चित नहीं है कि आपके द्वारा "कचरा बीनने वाले को चलाने की आवश्यकता है" से क्या मतलब है। जिन स्थितियों से बचने के लिए आवेदन की जरूरत है; आवंटन विफलताएं जो कभी संतुष्ट नहीं हो सकती हैं और उच्च जीसी ओवरहेड। अनियमित रूप से System.gc () पर कॉल करने से अक्सर उच्च GC ओवरहेड हो जाता है।
कर्क

@ किर्क - "अनियमित रूप से System.gc () पर कॉल करने से अक्सर उच्च GC ओवरहेड हो जाता है।" । मुझे पता है। तो क्या किसी ने मेरे उत्तर को पढ़ा और समझा होगा।
स्टीफन सी

@ किर्क - "पूरी तरह से निश्चित नहीं कि आपका क्या मतलब है ..." - मेरा मतलब ऐसे कार्यक्रमों से है जहां एक कार्यक्रम का "सही" व्यवहार एक विशेष समय पर चल रहे जीसी पर निर्भर करता है; उदाहरण के लिए अंतिम रूप से निष्पादित करने के लिए, या WeakReferences या SoftReferences को तोड़ने के लिए। यह करना बहुत बुरा विचार है ... लेकिन यह वही है जो मैं बात कर रहा हूं। स्टीवन श्लांसकर का उत्तर भी देखें।
स्टीफन सी

47

बहुत से लोग आपको ऐसा नहीं करने के लिए कह रहे हैं। मैं असहमत हूं। यदि, एक बड़ी लोडिंग प्रक्रिया के बाद जैसे एक स्तर लोड हो रहा है, तो आप मानते हैं कि:

  1. आपके पास बहुत सी वस्तुएं हैं जो अगम्य हैं और शायद gc'ed नहीं है। तथा
  2. आपको लगता है कि उपयोगकर्ता इस बिंदु पर एक छोटी मंदी के साथ रख सकता है

System.gc () को कॉल करने में कोई बुराई नहीं है। मैं इसे c / c ++ inlineकीवर्ड की तरह देखता हूं । यह सिर्फ एक संकेत है कि आप, डेवलपर, ने तय किया है कि समय / प्रदर्शन उतना महत्वपूर्ण नहीं है जितना कि आमतौर पर होता है और यह कि इसमें से कुछ का उपयोग मेमोरी को पुनः प्राप्त करने के लिए किया जा सकता है।

कुछ भी करने के लिए इस पर भरोसा न करने की सलाह सही है। इसे काम करने पर भरोसा मत करो, लेकिन यह संकेत देना कि अब इकट्ठा करने का एक स्वीकार्य समय पूरी तरह से ठीक है। जब उपयोगकर्ता सक्रिय रूप से प्रोग्राम के साथ इंटरेक्ट कर रहा होता है (जैसे गेम के स्तर के दौरान) तो कोड में एक बिंदु पर समय बर्बाद करना चाहिए, जहां यह स्क्रीन लोड नहीं करता है।

एक समय है जब मैं संग्रह को मजबूर करूंगा : जब यह पता लगाने का प्रयास किया जाता है कि एक विशेष वस्तु लीक है (या तो देशी कोड या बड़े, जटिल कॉलबैक इंटरैक्शन। ओह और कोई यूआई घटक जो मैटलैब पर इतना दिखता है।) इसका उपयोग कभी नहीं किया जाना चाहिएउत्पादन कोड में।


3
मेम लीक के लिए विश्लेषण करते समय जीसी के लिए +1। ध्यान दें कि ढेर उपयोग (Runtime.freeMemory () et al।) के बारे में जानकारी वास्तव में केवल एक GC मजबूर करने के बाद सार्थक है, अन्यथा यह इस पर निर्भर करेगा कि सिस्टम अंतिम बार GC चलाने के लिए कैसे परेशान होता है।
सेल्के

4
System.gc () को कॉल करने में कोई बुराई नहीं है, इसके लिए stop the worldदृष्टिकोण की आवश्यकता हो सकती है और यह एक वास्तविक नुकसान है, यदि ऐसा होता है
bestsss

7
वहाँ है कचरा कलेक्टर को स्पष्ट रूप से बुला में नुकसान। गलत समय पर GC को कॉल करने से CPU साइकिल बर्बाद हो जाती है। आप (प्रोग्रामर) के पास यह निर्धारित करने के लिए पर्याप्त जानकारी नहीं है कि सही समय कब है ... लेकिन जेवीएम करता है।
स्टीफन सी

Jetty स्टार्टअप के बाद System.gc () को 2 कॉल करता है और मैंने शायद ही कभी देखा है कि इससे कोई फर्क पड़ता है।
कर्क

वैसे जेटी डेवलपर्स के पास एक बग है। इससे फर्क पड़ेगा ... भले ही अंतर को निर्धारित करना मुश्किल हो।
स्टीफन सी

31

लोग यह बताने के लिए एक अच्छा काम कर रहे हैं कि क्यों न उपयोग किया जाए, इसलिए मैं आपको कुछ ऐसी स्थितियाँ बताऊँगा जहाँ आपको इसका उपयोग करना चाहिए:

(निम्नलिखित टिप्पणियां सीएमएस कलेक्टर के साथ लिनक्स पर चलने वाले हॉटस्पॉट पर लागू होती हैं, जहां मुझे यह कहते हुए आत्मविश्वास महसूस System.gc()होता है कि वास्तव में हमेशा एक पूर्ण कचरा संग्रह होता है)।

  1. अपने आवेदन को शुरू करने के प्रारंभिक कार्य के बाद, आप स्मृति उपयोग की एक भयानक स्थिति हो सकते हैं। आपकी कार्यकाल की आधी पीढ़ी कचरे से भरी हो सकती है, जिसका अर्थ है कि आप अपने पहले सीएमएस के बहुत करीब हैं। उन मामलों में जहां यह मायने रखता है, लाइव डेटा की प्रारंभिक अवस्था में अपने ढेर को "रीसेट" करने के लिए System.gc () को कॉल करना कोई बुरा विचार नहीं है।

  2. # 1 जैसी ही पंक्तियों के साथ, यदि आप अपने ढेर के उपयोग की बारीकी से निगरानी करते हैं, तो आप चाहते हैं कि आपके बेसलाइन मेमोरी उपयोग की सटीक रीडिंग हो। यदि आपके एप्लिकेशन के अपटाइम का पहला 2 मिनट सभी आरंभिक है, तो आपका डेटा गड़बड़ होने वाला है जब तक कि आप (ahem ... "सुझाव") को पूरा gc आगे नहीं बढ़ाते।

  3. आपके पास एक ऐसा एप्लिकेशन हो सकता है जिसे डिज़ाइन किए गए कार्यकाल के दौरान किसी भी चीज़ को बढ़ावा देने के लिए कभी नहीं बनाया गया हो। लेकिन हो सकता है कि आपको कुछ डेटा अप-फ्रंट को इनिशियलाइज़ करने की ज़रूरत हो जो इतना बड़ा न हो कि स्वचालित रूप से टेन्योर जेनरेशन में चला जाए। जब तक आप सब कुछ सेट होने के बाद System.gc () को कॉल नहीं करते, तब तक आपका डेटा नई पीढ़ी में बैठ सकता है जब तक कि इसके प्रचार का समय नहीं आता। अचानक आपके सुपर-डुपर कम-विलंबता, कम-जीसी एप्लिकेशन को सामान्य ऑपरेशन के दौरान उन वस्तुओं को बढ़ावा देने के लिए एक बड़ा (अपेक्षाकृत बोलने वाला, निश्चित रूप से) विलंबता जुर्माना मिलता है।

  4. मेमोरी लीक के अस्तित्व की पुष्टि करने के लिए एक उत्पादन अनुप्रयोग में उपलब्ध System.gc कॉल के लिए कभी-कभी उपयोगी होता है। यदि आप जानते हैं कि समय पर लाइव डेटा का सेट X, Y के समय लाइव डेटा के सेट के लिए एक निश्चित अनुपात में मौजूद होना चाहिए, तो यह System.gc () को एक बार X और समय Y को कॉल करने और मेमोरी उपयोग की तुलना करने के लिए उपयोगी हो सकता है ।


1
अधिकांश पीढ़ीगत कचरा संग्रहकर्ताओं के लिए, नई पीढ़ी की वस्तुओं को कचरा संग्रह की एक निश्चित (अक्सर कॉन्फ़िगर करने योग्य) संख्या से बचना पड़ता है, इसलिए System.gc()वस्तुओं को बढ़ावा देने के लिए एक बार कॉल करने से आपको कुछ भी हासिल नहीं होता है। और आप निश्चित रूप System.gc()से एक पंक्ति में आठ बार फोन नहीं करना चाहते हैं और प्रार्थना करते हैं कि अब, पदोन्नति हो गई है और बाद में पदोन्नति की सहेजी गई लागत कई पूर्ण जीसी की लागतों को सही ठहराती है। जीसी एल्गोरिथ्म के आधार पर, बहुत सी वस्तुओं को बढ़ावा देने से वास्तविक लागत भी नहीं लग सकती है, क्योंकि यह पुरानी पीढ़ी को मेमोरी को फिर से असाइन करेगा या समवर्ती कॉपी करेगा ...
होल्गर

11

यह एक बहुत ही परेशान करने वाला प्रश्न है, और मुझे लगता है कि यह भाषा के लिए उपयोगी होने के बावजूद जावा के विरोध में कई योगदान देता है।

यह तथ्य कि आप कुछ भी करने के लिए "System.gc" पर भरोसा नहीं कर सकते हैं, अविश्वसनीय रूप से चुनौतीपूर्ण है और आसानी से भाषा के लिए "डर, अनिश्चितता, संदेह" महसूस कर सकते हैं।

कई मामलों में, मेमोरी स्पाइक्स से निपटने के लिए अच्छा है कि आप एक महत्वपूर्ण घटना होने से पहले उद्देश्य पर चलते हैं, जिसके कारण उपयोगकर्ता सोचेंगे कि आपका कार्यक्रम बुरी तरह से डिज़ाइन किया गया है / अनुत्तरदायी है।

कचरा संग्रह को नियंत्रित करने की क्षमता होना एक बहुत अच्छा शिक्षा उपकरण होगा, जिससे लोगों की समझ में सुधार होगा कि कचरा संग्रह कैसे काम करता है और कैसे प्रोग्राम का शोषण होता है यह डिफ़ॉल्ट व्यवहार के साथ-साथ नियंत्रित व्यवहार भी है।

मुझे इस सूत्र के तर्कों की समीक्षा करने दें।

  1. यह अक्षम है:

अक्सर, प्रोग्राम कुछ भी नहीं कर सकता है और आपको पता है कि जिस तरह से डिज़ाइन किया गया था, उसके कारण यह कुछ भी नहीं कर रहा है। उदाहरण के लिए, यह एक बड़े प्रतीक्षा संदेश बॉक्स के साथ किसी प्रकार का लंबा इंतजार कर सकता है, और अंत में यह कचरा इकट्ठा करने के लिए कॉल भी जोड़ सकता है क्योंकि इसे चलाने का समय वास्तव में समय का एक छोटा सा अंश लगेगा लंबा इंतजार लेकिन एक और अधिक महत्वपूर्ण ऑपरेशन के बीच में कार्य करने से जीसी से बचना होगा।

  1. यह हमेशा एक बुरा अभ्यास है और टूटे हुए कोड को इंगित करता है।

मैं असहमत हूं, इससे कोई फर्क नहीं पड़ता कि आपके पास कौन सा कचरा इकट्ठा करने वाला है। इसका काम कचरा ट्रैक करना और उसे साफ करना है।

समय के दौरान gc को कॉल करने से जहां उपयोग कम महत्वपूर्ण होता है, आप इसे तब कम कर देते हैं, जब आपका जीवन विशिष्ट कोड के चलने पर निर्भर करता है, लेकिन इसके बजाय यह कचरा इकट्ठा करने का निर्णय लेता है।

निश्चित रूप से, यह आपके इच्छित तरीके या अपेक्षा का व्यवहार नहीं कर सकता है, लेकिन जब आप इसे कॉल करना चाहते हैं, तो आप जानते हैं कि कुछ भी नहीं हो रहा है, और उपयोगकर्ता धीमे / डाउनटाइम को सहन करने के लिए तैयार है। अगर System.gc काम करता है, तो बढ़िया है! यदि ऐसा नहीं होता है, तो कम से कम आपने कोशिश की। जब तक कचरा कलेक्टर में अंतर्निहित साइड इफेक्ट नहीं होता है, तब तक कोई नीचे की तरफ नहीं होता है, अगर कचरा कलेक्टर को मैन्युअल रूप से आमंत्रित किया जाता है, तो यह कैसे व्यवहार किया जाता है, और यह अविश्वास का कारण बनता है।

  1. यह एक आम उपयोग मामला नहीं है:

यह एक ऐसा उपयोग मामला है जो मज़बूती से हासिल नहीं किया जा सकता है, लेकिन यह हो सकता है कि सिस्टम को इस तरह से डिज़ाइन किया गया हो। यह एक ट्रैफिक लाइट बनाने और इसे बनाने जैसा है ताकि ट्रैफिक लाइट के कुछ / सभी बटन कुछ भी न करें, यह आपको सवाल बनाता है कि बटन के साथ शुरू करने के लिए क्यों है, जावास्क्रिप्ट में कचरा संग्रह कार्य नहीं है इसलिए हम डॉन करते हैं 'इसके लिए ज्यादा से ज्यादा छानबीन करें।

  1. युक्ति कहती है कि System.gc () एक संकेत है कि GC को चलना चाहिए और VM इसे अनदेखा करने के लिए स्वतंत्र है।

एक "संकेत" क्या है? "अनदेखा" क्या है? एक कंप्यूटर केवल संकेत नहीं ले सकता है या कुछ को अनदेखा नहीं कर सकता है, ऐसे सख्त व्यवहार पथ हैं जो कि गतिशील हो सकते हैं जो सिस्टम के इरादे से निर्देशित होते हैं। एक उचित उत्तर में शामिल होगा कि कचरा संग्रहकर्ता वास्तव में कार्यान्वयन स्तर पर क्या कर रहा है, इसके कारण यह है कि जब आप अनुरोध करते हैं तो यह संग्रह नहीं कर सकता है। क्या सुविधा केवल एक झपकी है? क्या मुझे किसी तरह की शर्तें पूरी करनी चाहिए? ये क्या स्थितियां हैं?

जैसा कि यह खड़ा है, जावा की जीसी अक्सर एक राक्षस की तरह लगती है जिसे आप अभी भरोसा नहीं करते हैं। आप नहीं जानते कि कब आना या जाना है, आप नहीं जानते कि यह क्या करने जा रहा है, यह कैसे करने जा रहा है। मैं कुछ विशेषज्ञों की कल्पना कर सकता हूं कि उनका कचरा संग्रह प्रति निर्देश के आधार पर कैसे काम करता है, लेकिन विशाल बहुमत यह उम्मीद करता है कि यह "बस काम करता है", और आपके लिए काम करने के लिए एक अपारदर्शी-प्रतीत होने वाले एल्गोरिथ्म पर भरोसा करना निराशाजनक है।

किसी चीज के बारे में पढ़ने या कुछ पढ़ाए जाने के बीच एक बड़ा अंतर है, और वास्तव में इसे लागू करने, प्रणालियों के अंतरों को देखने और स्रोत कोड को देखने के बिना इसके साथ खेलने में सक्षम होने के बीच। इससे आत्मविश्वास / समझ / नियंत्रण की भावना पैदा होती है।

संक्षेप में, जवाब के साथ एक अंतर्निहित समस्या है "यह सुविधा कुछ भी नहीं कर सकती है, और मैं विवरण में नहीं जाऊंगा कि यह कैसे बताना है कि यह कब कुछ करता है और कब नहीं और क्यों नहीं करेगा या नहीं करेगा।" अक्सर इसका मतलब यह है कि यह केवल इसे करने की कोशिश करने के लिए दर्शन के खिलाफ है, भले ही इसके पीछे का इरादा उचित हो ”।

जावा जीसी के लिए यह ठीक हो सकता है कि वह जिस तरह से व्यवहार करता है, या वह नहीं कर सकता है, लेकिन इसे समझने के लिए, यह वास्तव में पालन करना मुश्किल है कि किस दिशा में जाने के लिए आप जीसी पर भरोसा कर सकते हैं और क्या करना है ऐसा नहीं करना है, इसलिए यह बहुत आसान है कि भाषा को अविश्वास करें, क्योंकि भाषा का उद्देश्य दार्शनिक सीमा तक व्यवहार को नियंत्रित करना है (यह एक प्रोग्रामर के लिए आसान है, विशेष रूप से नौसिखिया कुछ प्रणाली / भाषा व्यवहार से अस्तित्वगत संकट में पड़ने के लिए) सहन करने में सक्षम हैं (और यदि आप नहीं कर सकते हैं, तो आप बस भाषा का उपयोग तब तक नहीं करेंगे जब तक आपके पास नहीं है), और अधिक चीजें जिन्हें आप बिना किसी ज्ञात कारण के नियंत्रित नहीं कर सकते हैं, क्योंकि आप उन्हें नियंत्रित नहीं कर सकते हैं स्वाभाविक रूप से हानिकारक हैं।


9

जीसी दक्षता कई सांख्यिकी पर निर्भर करती है। उदाहरण के लिए, एक सामान्य अनुमानी यह है कि वस्तुओं तक पहुंच लिखना आमतौर पर उन वस्तुओं पर होता है जो बहुत पहले नहीं बनाई गई थीं। एक और बात यह है कि कई वस्तुएं बहुत ही अल्पकालिक हैं (कुछ वस्तुओं का उपयोग लंबे समय तक किया जाएगा, लेकिन कई को उनके निर्माण के बाद कुछ माइक्रोसेकंड को छोड़ दिया जाएगा)।

कॉल System.gc()करना जीसी को लात मारने जैसा है। इसका अर्थ है: "उन सभी को ध्यान से देखते हुए मापदंडों, उन स्मार्ट संगठनों, उन सभी प्रयासों को जो आप वस्तुओं को आवंटित करने और प्रबंधित करने में लगाते हैं, जैसे कि चीजें आसानी से चलती हैं, ठीक है, बस पूरी तरह से छोड़ दें, और खरोंच से शुरू करें"। यह प्रदर्शन में सुधार कर सकता है , लेकिन ज्यादातर समय यह प्रदर्शन को कम करता है।

System.gc()मज़बूती से उपयोग करने के लिए (*) आपको यह जानना होगा कि जीसी अपने सभी बारीक विवरणों को कैसे संचालित करता है। यदि आप किसी अन्य विक्रेता से JVM, या उसी विक्रेता से अगला संस्करण, या उसी JVM का उपयोग करते हैं, लेकिन थोड़े अलग-अलग कमांड-लाइन विकल्पों के साथ इस तरह के विवरण काफी बदल जाते हैं। इसलिए यह शायद ही कभी एक अच्छा विचार है, जब तक कि आप एक विशेष मुद्दे को संबोधित नहीं करना चाहते जिसमें आप उन सभी मापदंडों को नियंत्रित करते हैं। इसलिए "बुरे अभ्यास" की धारणा: यह निषिद्ध नहीं है, विधि मौजूद है, लेकिन यह शायद ही कभी भुगतान करता है।

(*) मैं यहां दक्षता के बारे में बात कर रहा हूं। System.gc()कभी भी एक सही जावा प्रोग्राम नहीं तोड़ेंगे । यह न तो अतिरिक्त मेमोरी को संभालेगा OutOfMemoryError, जिसे JVM अन्यथा प्राप्त नहीं कर सकता था: एक फेंकने से पहले , JVM System.gc()एक अंतिम उपाय के रूप में , भले ही काम करता हो ।


1
+1 यह उल्लेख करने के लिए कि System.gc () OutOfMemoryError को रोकता नहीं है। कुछ लोग ऐसा मानते हैं।
सेलेक

1
वास्तव में, यह नरम संदर्भ से निपटने के कारण OutOfMemoryError को रोक सकता है । पिछले GC रन के बाद बनाए गए SoftReferences कार्यान्वयन में एकत्र नहीं होते हैं जो मुझे पता है। लेकिन यह कार्यान्वयन विस्तार विषय कभी भी और किसी भी प्रकार के बग को बदलने के लिए होता है और कुछ भी नहीं जिस पर आपको भरोसा करना चाहिए।
मातरिनस

8

कभी-कभी ( अक्सर नहीं! ) आप वास्तव में अतीत, वर्तमान और भविष्य की स्मृति के उपयोग के बारे में अधिक जानते हैं तो रन टाइम करता है। यह बहुत बार नहीं होता है, और मैं दावा करता हूं कि वेब एप्लिकेशन में कभी नहीं होगा जबकि सामान्य पृष्ठ परोसे जा रहे हैं।

कई साल पहले मैं एक रिपोर्ट जनरेटर पर काम करता हूं, वह

  • एक ही धागा था
  • एक कतार से "रिपोर्ट अनुरोध" पढ़ें
  • डेटाबेस से रिपोर्ट के लिए आवश्यक डेटा लोड किया गया
  • रिपोर्ट तैयार की और उसे ईमेल किया।
  • कोई बकाया अनुरोध नहीं होने पर हमेशा के लिए सो गया।
  • इसने रिपोर्टों के बीच किसी भी डेटा का पुन: उपयोग नहीं किया और न ही कोई कैशिंग किया।

सबसे पहले चूंकि यह वास्तविक समय नहीं था और उपयोगकर्ताओं को एक रिपोर्ट की प्रतीक्षा करने की उम्मीद थी, जबकि जीसी रन एक मुद्दा नहीं था, लेकिन हमें उन दर पर रिपोर्ट तैयार करने की आवश्यकता थी जो उनसे अनुरोध किए गए थे।

प्रक्रिया की उपरोक्त रूपरेखा को देखते हुए, यह स्पष्ट है कि।

  • हमें पता है कि रिपोर्ट दर्ज होने के ठीक बाद बहुत कम जीवित वस्तुएं होंगी, क्योंकि अगले अनुरोध पर अभी तक कार्रवाई शुरू नहीं हुई थी।
  • यह सर्वविदित है कि कचरा संग्रह चक्र चलाने की लागत जीवित वस्तुओं की संख्या पर निर्भर करती है , जीसी रन की लागत पर कचरे की मात्रा का बहुत कम प्रभाव पड़ता है।
  • कि जब कतार खाली हो तो कुछ भी करना बेहतर नहीं है तो जीसी चलाएं।

इसलिए स्पष्ट रूप से यह अच्छी तरह से लायक था जब भी अनुरोध कतार खाली थी, जीसी चलाते थे; इस के लिए कोई नकारात्मक पहलू नहीं था।

यह प्रत्येक रिपोर्ट के ईमेल के बाद जीसी रन करने के लायक हो सकता है, क्योंकि हम जानते हैं कि यह जीसी रन के लिए एक अच्छा समय है। हालाँकि, यदि कंप्यूटर में पर्याप्त रैम थी, तो GC रन में देरी से बेहतर परिणाम प्राप्त होंगे।

यह व्यवहार प्रति इंस्टॉलेशन बेस पर कॉन्फ़िगर किया गया था, कुछ ग्राहकों ने प्रत्येक रिपोर्ट के बाद रिपोर्ट की सुरक्षा को बहुत तेज करने के बाद एक मजबूर GC को सक्षम किया । (मुझे उम्मीद है कि यह उनके सर्वर पर कम मेमोरी के कारण था और यह बहुत सारी अन्य प्रक्रियाएं चला रहा था, इसलिए इसलिए अच्छी तरह से मजबूर जीसी ने पेजिंग को कम कर दिया।)

हमने कभी भी ऐसी स्थापना का पता नहीं लगाया जिससे लाभ न हुआ हो, हर बार जब काम की कतार खाली होती थी तो एक मजबूर जीसी चलता था।

लेकिन, स्पष्ट होने दें, ऊपर एक सामान्य मामला नहीं है।


3

हो सकता है कि मैं भद्दा कोड लिखूं, लेकिन मुझे एहसास हुआ है कि ग्रहण और netbeans IDE पर ट्रैश-कैन आइकन पर क्लिक करना एक 'अच्छा अभ्यास' है।


1
ऐसा हो सकता है। लेकिन अगर ग्रहण या नेटबीन्स को System.gc()समय-समय पर कॉल करने के लिए प्रोग्राम किया गया था , तो आप शायद व्यवहार को कष्टप्रद पाएंगे।
स्टीफन C

2

पहले, कल्पना और वास्तविकता के बीच अंतर है। युक्ति कहती है कि System.gc () एक संकेत है कि GC को चलना चाहिए और VM इसे अनदेखा करने के लिए स्वतंत्र है। वास्तविकता यह है कि, VM कभी भी System.gc () को कॉल को अनदेखा नहीं करेगा ।

कॉलिंग GC एक गैर-तुच्छ ओवरहेड कॉल के साथ आता है और यदि आप समय पर कुछ यादृच्छिक बिंदु पर ऐसा करते हैं, तो संभावना है कि आप अपने प्रयासों के लिए कोई इनाम नहीं देखेंगे। दूसरी ओर, स्वाभाविक रूप से ट्रिगर किया गया संग्रह कॉल की लागतों की पुनरावृत्ति करने की बहुत संभावना है। यदि आपके पास ऐसी जानकारी है जो इंगित करती है कि GC को चलाया जाना चाहिए, तो आप System.gc () को कॉल कर सकते हैं और आपको लाभ देखना चाहिए। हालाँकि, यह मेरा अनुभव है कि ऐसा केवल कुछ धार वाले मामलों में ही होता है क्योंकि यह बहुत कम संभावना है कि आपको यह समझने के लिए पर्याप्त जानकारी होगी कि क्या और कब System.gc () को बुलाया जाना चाहिए।

एक उदाहरण यहाँ सूचीबद्ध है, कचरा आपके IDE में मार सकता है। यदि आप एक बैठक के लिए रवाना हो रहे हैं तो क्यों नहीं मारा। ओवरहेड आपको प्रभावित करने वाला नहीं है और जब आप वापस आते हैं तो ढेर को साफ किया जा सकता है। एक उत्पादन प्रणाली में ऐसा करें और इकट्ठा करने के लिए लगातार कॉल करने से यह एक पीस पड़ाव में आ जाएगा! यहां तक ​​कि कभी-कभी कॉल जैसे कि आरएमआई द्वारा किए गए प्रदर्शन के लिए विघटनकारी हो सकते हैं।


3
"वास्तविकता यह है कि, VM कभी भी System.gc () के लिए कॉल को अनदेखा नहीं करेगा।" - गलत है। -XX के बारे में पढ़ें: -DisableExplicitGC
स्टीफन सी

1

हां, System.gc () को कॉल करना यह गारंटी नहीं देता है कि यह चलेगा, यह JVM के लिए एक अनुरोध है जिसे अनदेखा किया जा सकता है। डॉक्स से:

जीसी विधि को कॉल करने से पता चलता है कि जावा वर्चुअल मशीन अप्रयुक्त वस्तुओं को रीसाइक्लिंग करने की दिशा में प्रयास करती है

इसे कॉल करना लगभग हमेशा एक बुरा विचार है क्योंकि स्वचालित मेमोरी प्रबंधन आमतौर पर आपसे बेहतर जानता है कि कब जी.सी. ऐसा तब होगा जब इसकी मुफ्त मेमोरी का आंतरिक पूल कम है, या यदि ओएस अनुरोध करता है कि कुछ मेमोरी वापस दी जाए।

यदि आप जानते हैं कि यह मदद करता है तो System.gc () को कॉल करना स्वीकार्य हो सकता है । इसका मतलब है कि आपने तैनाती मंच पर दोनों परिदृश्यों के व्यवहार को अच्छी तरह से परखा और मापा है , और आप यह दिखा सकते हैं कि यह मदद करता है। हालांकि यह जान लें कि gc आसानी से अनुमानित नहीं है - यह एक रन पर मदद कर सकता है और दूसरे पर चोट कर सकता है।


<string> लेकिन Javadoc से भी: _When नियंत्रण कॉल विधि से वापस आती है, वर्चुअल मशीन ने सभी खारिज की गई वस्तुओं को रीसायकल करने का अपना सर्वश्रेष्ठ प्रयास किया है, जिसे मैं आपके द्वारा पोस्ट किए गए एक अधिक आवश्यक रूप के रूप में देखता हूं। </ string > पेंच है कि, इसके बारे में एक गलत रिपोर्ट है जो भ्रामक है। जैसा कि बेहतर जानता है, जेवीएम को इंगित करने के क्या नुकसान हैं?
zneak

1
नुकसान यह है कि गलत समय पर संग्रह करना एक बड़ी धीमी गति हो सकती है। संकेत आप दे रहे हैं शायद एक बुरा है। "सर्वश्रेष्ठ प्रयास" टिप्पणी के लिए, इसे आज़माएं और JConsole जैसे टूल में देखें। कभी कभी "जीसी प्रदर्शन" बटन पर क्लिक कुछ नहीं करता है
टॉम

OpenJDK में System.gc () और उस पर आधारित कुछ भी (उदाहरण के लिए HP) को कॉल करने से असहमत होने के लिए खेद है, हमेशा कचरा संग्रह चक्र में परिणाम होता है। वास्तव में यह आईबीएम के जे 9 कार्यान्वयन के बारे में भी सच है
किर्क

@ किर्क - गलत: गूगल, और पढ़ने के बारे में -XX: -DisableExplicitGC।
स्टीफन सी

0

मेरे अनुभव में, System.gc () का उपयोग प्रभावी रूप से अनुकूलन का एक प्लेटफ़ॉर्म-विशिष्ट रूप है (जहाँ "प्लेटफ़ॉर्म" हार्डवेयर आर्किटेक्चर, OS, JVM संस्करण और RAM जैसे संभावित रनटाइम मापदंडों का संयोजन है), क्योंकि इसका व्यवहार, जबकि एक विशिष्ट मंच पर लगभग अनुमान लगाया जा सकता है, (और कर सकते हैं) प्लेटफार्मों के बीच काफी भिन्नता है।

हां, ऐसी परिस्थितियां हैं जहां System.gc () में सुधार (कथित) प्रदर्शन होगा। उदाहरण के लिए, यदि आपके ऐप के कुछ हिस्सों में देरी सहन करने योग्य है, लेकिन दूसरों में नहीं (खेल का उदाहरण ऊपर उद्धृत किया गया है, जहां आप चाहते हैं कि जीसी एक स्तर की शुरुआत में हो, न कि स्तर के दौरान)।

हालांकि, यह मदद करेगा या चोट करेगा (या कुछ भी नहीं) मंच पर अत्यधिक निर्भर है (जैसा कि ऊपर बताया गया है)।

इसलिए मुझे लगता है कि यह अंतिम-रिज़ॉर्ट प्लेटफ़ॉर्म-विशिष्ट अनुकूलन के रूप में मान्य है (अर्थात यदि अन्य प्रदर्शन अनुकूलन पर्याप्त नहीं हैं)। लेकिन आपको इसे कभी भी केवल इसलिए नहीं बुलाना चाहिए क्योंकि आपको लगता है कि यह (विशिष्ट बेंचमार्क के बिना) मदद कर सकता है, क्योंकि संभावना है कि यह नहीं होगा।


0
  1. चूंकि ऑब्जेक्ट्स को नए ऑपरेटर का उपयोग करके गतिशील रूप से आवंटित किया जाता है,
    आप सोच रहे होंगे कि ऐसी वस्तुएं कैसे नष्ट हो जाती हैं और
    बाद में पुनः प्राप्ति के लिए उनकी मेमोरी जारी की जाती है।

  2. कुछ भाषाओं में, जैसे कि सी ++, डायनामिक रूप से आवंटित ऑब्जेक्ट को मैन्युअल रूप से एक डिलीट ऑपरेटर के उपयोग से जारी किया जाना चाहिए।

  3. जावा एक अलग दृष्टिकोण लेता है; यह आपके लिए स्वचालित रूप से डीलक्लोकेशन संभालता है।
  4. इसे पूरा करने वाली तकनीक को कचरा संग्रह कहा जाता है। यह इस तरह से काम करता है: जब किसी वस्तु का कोई संदर्भ मौजूद नहीं होता है, तो उस वस्तु की अब आवश्यकता नहीं मानी जाती है, और ऑब्जेक्ट द्वारा कब्जा की गई स्मृति को पुनः प्राप्त किया जा सकता है। C ++ की तरह वस्तुओं को नष्ट करने की कोई स्पष्ट आवश्यकता नहीं है।
  5. कचरा संग्रहण केवल आपके कार्यक्रम के निष्पादन के दौरान छिटपुट रूप से (यदि हो तो) होता है।
  6. यह केवल इसलिए नहीं होगा क्योंकि एक या अधिक ऑब्जेक्ट मौजूद हैं जो अब उपयोग नहीं किए जाते हैं।
  7. इसके अलावा, विभिन्न जावा रन-टाइम कार्यान्वयन कचरा संग्रहण के लिए अलग-अलग दृष्टिकोण लेंगे, लेकिन अधिकांश भाग के लिए, आपको अपने कार्यक्रम लिखते समय इसके बारे में नहीं सोचना चाहिए।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.