System.gc () कब कुछ करता है?


118

मुझे पता है कि कचरा संग्रह जावा में स्वचालित है। लेकिन मैं समझ गया कि यदि आप System.gc()अपने कोड में कहते हैं कि JVM उस बिंदु पर कचरा संग्रह करने का निर्णय ले सकता है या नहीं। यह कैसे ठीक काम करता है? किस आधार / पैरामीटर पर जेवीएम एक जीसी को देखने (या न करने) का निर्णय करता है जब वह देखता है System.gc()?

क्या कोई उदाहरण है जिस स्थिति में इसे अपने कोड में रखना एक अच्छा विचार है?


4
एक अवधारणा के बहुत जटिल यहाँ पूर्ण विवरण के लिए, लेकिन इस लेख में आपकी मदद करनी चाहिए: chaoticjava.com/posts/how-does-garbage-collection-work
GEOCHET

सटीक व्यवहार जेवीएम पर निर्भर है, यानी कार्यान्वयन निर्भर।
थोरबजोरन रावन एंडरसन

जवाबों:


59

व्यवहार में, यह आमतौर पर एक कचरा संग्रह करने का फैसला करता है। यह उत्तर बहुत सारे कारकों के आधार पर भिन्न होता है, जैसे कि आप किस JVM पर चल रहे हैं, यह किस मोड में है और कौन सा कचरा संग्रह एल्गोरिदम इसका उपयोग कर रहा है।

मैं आपके कोड में इस पर निर्भर नहीं होता। यदि JVM एक OutOfMemoryError को फेंकने वाला है, तो System.gc () को कॉल करना बंद नहीं करेगा, क्योंकि कचरा संग्रहकर्ता उस चरम पर जाने से पहले जितना संभव हो उतना मुक्त करने का प्रयास करेगा। केवल समय मैंने इसे अभ्यास में उपयोग किया है यह आईडीई में है जहां यह एक बटन से जुड़ा हुआ है जिसे एक उपयोगकर्ता क्लिक कर सकता है, लेकिन यहां तक ​​कि यह बहुत उपयोगी नहीं है।


3
आप जोंको कंसोल में एक कचरा संग्रह के लिए मजबूर कर सकते हैं
बेनेडिकट वाल्डवोगेल

25
क्या आप वाकई इसे "बल" दे सकते हैं? क्या jconsole सिर्फ System.gc () कह रहा है?
जॉन मेघेर

4
मैं System.gc()वीडियो गेम के लिए लोडिंग स्क्रीन में उपयोग करूंगा । उस समय, मैं वास्तव में परवाह नहीं करता अगर कॉल ने सबकुछ साफ कर दिया जो संभवतः संभव हो, या बिल्कुल भी कुछ नहीं किया। हालाँकि, मैं यह पसंद करूँगा कि यह "अप्रयुक्त वस्तुओं के पुनर्चक्रण की दिशा में प्रयास" लोडिंग स्क्रीन के दौरान, बजाय गेमप्ले के दौरान करे।
क्रॉ

30

एकमात्र उदाहरण मैं सोच सकता हूं कि यह कहां से आता है जिसे System.gc कहा जाता है। () जब संभव हो तो मैमोरी लीक की खोज के लिए किसी एप्लिकेशन को प्रोफाइल करना। मेरा मानना ​​है कि प्रोफाइलर्स स्नैपशॉट लेने से ठीक पहले इस विधि को कहते हैं।


4
हां, मैं भी यही करता हूं। Runtime.freeMemory () उदा द्वारा लौटाए गए मान केवल System.gc () के बाद वास्तव में सार्थक हैं, क्योंकि आम तौर पर आप जानना चाहते हैं कि अचूक उदाहरणों से कितनी मेमोरी अवरुद्ध होती है। केवल डिबगिंग / मेमोरी प्रोफाइलिंग में उपयोग किया जाना है, उत्पादन में कभी नहीं।
sleske

Naw, कई अन्य परिदृश्यों के लिए भी अच्छा है। उदाहरण के लिए, मान लें कि आपके पास एक एकल पैटर्न है जो जीवन चक्र से अवगत है। OnStop () में यदि आप उदाहरण के लिए अशक्त (आईएनजी) हैं, तो इसे मदद करने के लिए System.gc () को कॉल करना एक अच्छा विचार है।
portfoliobuilder

26

जावा लैंग्वेज स्पेसिफिकेशन इस बात की गारंटी नहीं देता है कि जेवीएम आपके कॉल करने पर जीसी शुरू करेगा System.gc()। यही कारण है कि "उस बिंदु पर जीसी करने का निर्णय लिया जा सकता है या नहीं"।

अब, यदि आप OpenJDK स्रोत कोड को देखते हैं , जो कि Oracle JVM की रीढ़ है, तो आप देखेंगे कि System.gc()GC चक्र शुरू करने के लिए एक कॉल करता है। यदि आप किसी अन्य JVM, जैसे J9 का उपयोग करते हैं, तो आपको उत्तर जानने के लिए उनके दस्तावेज की जांच करनी होगी। उदाहरण के लिए, अज़ुल के जेवीएम में एक कचरा संग्रहकर्ता है जो लगातार चलता रहता है, इसलिए कॉल System.gc()कुछ भी नहीं कर सकता है

कुछ अन्य उत्तर में JConsole या VisualVM में GC शुरू करने का उल्लेख है। असल में, ये उपकरण एक दूरस्थ कॉल करते हैं System.gc()

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

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


26

जावा में जीसी पर आपका कोई नियंत्रण नहीं है - वीएम फैसला करता है। मैं एक मामले में जहां भर में कभी नहीं आई है System.gc()है की जरूरत । चूँकि System.gc()कॉल केवल SUGGESTS करता है कि VM एक कचरा संग्रह करता है और यह एक FULL कचरा संग्रह (एक बहु-पीढ़ीगत ढेर में पुरानी और नई पीढ़ी) भी करता है, तो यह वास्तव में आवश्यकता से अधिक सीपीयू चक्रों का उपभोग कर सकता है।

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


17

यदि आप फोन करते हैं तो आपको बहुत सावधान रहने की जरूरत है System.gc()। इसे कॉल करने से आपके एप्लिकेशन में अनावश्यक प्रदर्शन समस्याएं जुड़ सकती हैं, और यह वास्तव में संग्रह करने के लिए गारंटी नहीं है। System.gc()जावा तर्क के माध्यम से स्पष्ट रूप से अक्षम करना संभव है -XX:+DisableExplicitGC

मैं अत्यधिक कचरा संग्रह के बारे में गहराई से जानकारी के लिए जावा हॉटस्पॉट कचरा संग्रह में उपलब्ध दस्तावेजों के माध्यम से पढ़ने की सलाह दूंगा


मेरा Android एप्लिकेशन हमेशा मुझे एक OutOememoryException फेंकता है। इसलिए मैं सभी अवांछित संदर्भों और वस्तुओं को साफ करने के लिए अपनी कक्षा के onDestroy फ़ंक्शन में System.gc () का उपयोग करने के बारे में सोच रहा था। क्या यह एक अच्छा दृष्टिकोण है
सागर देवांग

2
@ सागर देवंगा मैन्युअल रूप से gc को कॉल करते हैं जैसा कि आप वर्णन करते हैं कि मदद करने की संभावना नहीं है। OOM फेंकने से पहले, JVM ने पहले से ही मेमोरी को खाली करने के लिए कचरा इकट्ठा करने का प्रयास किया होगा
Scrubbie

10

System.gc()VM द्वारा कार्यान्वित किया जाता है, और यह जो करता है वह कार्यान्वयन विशिष्ट है। उदाहरण के लिए, कार्यान्वयनकर्ता केवल वापस लौट सकता है और कुछ भी नहीं कर सकता है।

जब तक एक मैनुअल संग्रह जारी करने का समय होता है, तब केवल जब आप ऐसा करना चाहते हैं, जब आप एक बड़े संग्रह को छोड़ देते हैं, जिसमें छोटे संग्रह का भार होता है - Map<String,<LinkedList>> उदाहरण के लिए - और आप तब हिट करने की कोशिश करना चाहते हैं। वहाँ, लेकिन अधिकांश भाग के लिए, आपको इसकी चिंता नहीं करनी चाहिए। जीसी आपसे बेहतर जानता है - दुख की बात है - ज्यादातर समय।


8

यदि आप डायरेक्ट मेमोरी बफ़र्स का उपयोग करते हैं, तो JVM आपके लिए GC नहीं चलाता है, भले ही आप डायरेक्ट मेमोरी पर कम चल रहे हों।

यदि आप कॉल करते हैं ByteBuffer.allocateDirect()और आपको एक आउटऑफमेरीऑय्र मिलता है, तो आप मैन्युअल रूप से जीसी को ट्रिगर करने के बाद यह कॉल ठीक पा सकते हैं।


क्या आप कह रहे हैं कि System.gc () प्रत्यक्ष आवंटन एकत्र करता है जबकि JVM सामान्य रूप से (OOM फेंकने से पहले) नहीं करता है। क्योंकि मुझे लगता है कि यह गलत है। एक एकमात्र कारण यह हो सकता है कि एक एक्सप्लोसिट जीसी अतिरिक्त समय के बाद एक आवंटन हो सकता है और अंतिम-अंतिम मधुमक्खी मुक्त (और कुछ सीधे आवंटित वस्तु को मुक्त) के साथ इन-हीप ऑब्जेक्ट की कुछ अधिक संभावना है।
Eckes

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

1
धन्यवाद, यह मेरे अनुभव की तरह लगता है। इसलिए मुझे लगता है कि उत्तर पुराने जावा संस्करणों के लिए ही सही है।
Eckes

5

अधिकांश JVM एक GC को बंद कर देंगे (-XX के आधार पर: DiableExplicitGC और -XX: + ExplicitGCInvokesConcurrent स्विच)। लेकिन बाद में बेहतर क्रियान्वयन की अनुमति देने के लिए विनिर्देशन को कम अच्छी तरह से परिभाषित किया गया है।

युक्ति को स्पष्टीकरण की आवश्यकता है: बग # 6668279: (कल्पना) System.gc () इंगित करना चाहिए कि हम उपयोग की अनुशंसा नहीं करते हैं और व्यवहार की गारंटी नहीं देते हैं।

आंतरिक रूप से gc पद्धति का उपयोग RMI और NIO द्वारा किया जाता है, और उन्हें तुल्यकालिक निष्पादन की आवश्यकता होती है, जो: यह वर्तमान में चर्चा में है:

बग # 5025281: समसामयिक (स्टॉप-द-वर्ल्ड) पूर्ण संग्रह को ट्रिगर करने के लिए System.gc () को अनुमति दें


3

Garbage Collectionमें अच्छा है Java, अगर हम डेस्कटॉप / लैपटॉप / सर्वर में जावा में सॉफ्टवेयर कोडित निष्पादित कर रहे हैं। आप कॉल System.gc()या Runtime.getRuntime().gc()में कर सकते हैं Java

बस ध्यान दें कि उनमें से कोई भी कॉल कुछ भी करने की गारंटी नहीं है। वे केवल कचरा कलेक्टर को चलाने के लिए jvm के लिए एक सुझाव हैं। यह जेवीएम के ऊपर है कि वह जीसी चलाता है या नहीं। तो, संक्षिप्त उत्तर: हमें नहीं पता कि यह कब चलता है। लंबे समय तक उत्तर: जेवीएम के पास समय होगा अगर उसके पास समय हो।

मेरा मानना ​​है, Android के लिए भी यही बात लागू होती है। हालाँकि, यह आपके सिस्टम को धीमा कर सकता है।


जेवीएम जीसी चलाएगा अगर उसके लिए समय है : हमेशा सच नहीं, जेवीएम ईडी मेमोरी भर जाने पर जीसी चला सकता है।
abdelmouheimen

2

आम तौर पर, VM एक OutOfMemoryException को फेंकने से पहले स्वचालित रूप से एक कचरा संग्रह करता है, इसलिए एक स्पष्ट कॉल को जोड़ने में मदद नहीं करनी चाहिए सिवाय इसके कि यह प्रदर्शन को समय से पहले एक पल में हिट करता है।

हालांकि, मुझे लगता है कि मुझे एक ऐसे मामले का सामना करना पड़ा जहां यह प्रासंगिक हो सकता है। मुझे यकीन नहीं है, हालांकि, मुझे अभी तक परीक्षण करना है कि क्या इसका कोई प्रभाव है:

जब आप किसी फ़ाइल को मेमोरी-मैप करते हैं, तो मुझे विश्वास होता है कि मेमोरी का एक बड़ा ब्लॉक उपलब्ध नहीं होने पर मैप () कॉल एक आईओएक्स अपवाद फेंकता है। मानचित्र () फ़ाइल से ठीक पहले एक कचरा संग्रह मुझे रोकने में मदद कर सकता है, मुझे लगता है। तुम क्या सोचते हो?


2

हम कभी भी कचरा संग्रहण के लिए बाध्य नहीं कर सकते। System.gc केवल कचरा संग्रहण के लिए vm का सुझाव दे रहा है, हालांकि, वास्तव में तंत्र किस समय चलता है, कोई नहीं जानता, यह जेएसआर विनिर्देशों द्वारा कहा गया है।


2

विभिन्न कचरा संग्रहण सेटिंग्स का परीक्षण करने के लिए समय निकालने के लिए बहुत कुछ कहा जाता है, लेकिन जैसा कि ऊपर उल्लेख किया गया है, आमतौर पर ऐसा करने के लिए उपयोगी नहीं है।

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

नतीजतन, केवल एक बार मेरा आवेदन System.gc () कहता है, जब यह कोड के सेगमेंट में प्रवेश करने वाला होता है, जहां डेटा को संसाधित करने के लिए आवश्यक बड़े बफ़र्स आवंटित किए जाएंगे, और उपलब्ध मुफ्त मेमोरी पर एक परीक्षण इंगित करता है कि मैं नहीं हूं। इसकी गारंटी है। विशेष रूप से, मैं एक 1gb वातावरण को देख रहा हूं जहां कम से कम 300mb में स्थैतिक डेटा का कब्जा है, गैर-स्थैतिक डेटा के थोक के साथ निष्पादन-संबंधित होने के अलावा जब संसाधित होने वाले डेटा को कम से कम 100-200 एमबी होना चाहिए स्रोत। यह सभी स्वचालित डेटा रूपांतरण प्रक्रिया का हिस्सा है, इसलिए लंबे समय में अपेक्षाकृत कम समय के लिए डेटा मौजूद रहता है।

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

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


2

यदि आप जानना चाहते हैं कि क्या आपका System.gc()नाम पुकारा गया है, तो आप नए जावा 7 अपडेट 4 के साथ अधिसूचना प्राप्त कर सकते हैं जब जेवीएम कचरा संग्रह करता है।

मुझे 100% यकीन नहीं है कि GarbageCollectorMXBean वर्ग जावा 7 अपडेट 4 में पेश किया गया था, क्योंकि मैं इसे जारी नोटों में नहीं ढूंढ सका, लेकिन मुझे javaperformancetuning .com में जानकारी मिली


0

स्पष्ट जीसी को चलाने के लिए अच्छा होने पर मैं एक विशिष्ट उदाहरण के बारे में नहीं सोच सकता।

सामान्य तौर पर, स्पष्ट जीसी चलने से वास्तव में अच्छे से अधिक नुकसान हो सकता है, क्योंकि एक स्पष्ट जीसी एक पूर्ण संग्रह को ट्रिगर करेगा, जो हर वस्तु से गुजरने में काफी लंबा समय लेता है। अगर यह स्पष्ट जीसी समाप्त होता है बार-बार कहा जा रहा है तो यह आसानी से एक धीमी गति से आवेदन कर सकता है क्योंकि पूर्ण जीसीएस को चलाने में बहुत समय व्यतीत होता है।

वैकल्पिक रूप से यदि एक ढेर विश्लेषक के साथ ढेर पर जा रहा है और आपको संदेह है कि पुस्तकालय घटक को स्पष्ट GC कॉलिंग है, तो आप इसे जोड़ सकते हैं: gc = -XX: + JVM मापदंडों के लिए DisableExplicitGC।


2
हम अपने MappedByteBuffer ऑब्जेक्ट्स को बंद करने का प्रयास करने के लिए System.gc () को कॉल करते हैं जो अन्यथा बंद नहीं होते हैं, और इसलिए अन्य प्रक्रियाओं के लिए या फ़ाइल ट्रंकेशन के लिए उपलब्ध नहीं हैं, भले ही हम वस्तुओं पर 'बंद ()' कहते हैं। दुर्भाग्य से यह अभी भी हमेशा उन्हें बंद नहीं करता है।
टिम कूपर

0

ब्रूस एकेल द्वारा जावा में सोचने के लिए, स्पष्ट System.gc () कॉल के लिए एक उपयोग का मामला है जब आप अंतिम रूप देने के लिए बाध्य करना चाहते हैं, अर्थात कॉल को अंतिम रूप देने के लिए ।


NB: अंतिम रूप से चलाने के लिए बाध्य करने के लिए एक स्वयं की विधि है। (समस्या वास्तव में अंतिम रूप से चलने में नहीं है, लेकिन यह पहचानना कि किसी वस्तु को अंतिम रूप दिया जा सकता है क्योंकि यह
अप्रतिबंधित है

-1

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.