क्यों बड़े ऑब्जेक्ट हीप और हम क्यों परवाह करते हैं?


105

मैंने जनरेशन और लार्ज ऑब्जेक्ट हीप के बारे में पढ़ा है। लेकिन मैं अभी भी यह समझने में नाकाम हूं कि लार्ज ऑब्जेक्ट हीप होने का महत्व (या लाभ) क्या है?

क्या गलत हो सकता था (प्रदर्शन या स्मृति के मामले में) अगर CLR सिर्फ जेनरेशन 2 (Gen0 को ध्यान में रखते हुए और Gen1 बड़ी वस्तुओं को संभालने के लिए छोटा होता है) को ध्यान में रखते हुए बड़ी वस्तुओं के भंडारण पर निर्भर करता है?


6
यह मुझे .NET डिजाइनरों के लिए दो प्रश्न देता है: 1. आउटऑफमेरी एक्ससेप्शन से पहले एलओएच डीफ़्रेग क्यों नहीं कहा जाता है? 2. एलओएच ऑब्जेक्ट्स में एक साथ रहने के लिए एक आत्मीयता क्यों नहीं है (बड़े हीप के अंत को पसंद करते हैं और शुरुआत में छोटे होते हैं)
जैकब ब्रूअर

जवाबों:


195

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

कॉम्पैक्टिंग बस बाइट्स को कॉपी करके किया जाता है। हालांकि इसमें समय लगता है। बड़ी वस्तु, अधिक संभावना है कि इसे कॉपी करने की लागत संभव सीपीयू कैश उपयोग में सुधार से आगे निकल जाती है।

इसलिए उन्होंने ब्रेक-सम पॉइंट को निर्धारित करने के लिए बेंचमार्क का एक समूह चलाया। और कटऑफ पॉइंट के रूप में 85,000 बाइट्स पर पहुंचे जहां कॉपी करने से अब सुधार नहीं होता है। डबल के सरणियों के लिए एक विशेष अपवाद के साथ, उन्हें 'बड़ा' माना जाता है जब सरणी में 1000 से अधिक तत्व होते हैं। यह 32-बिट कोड के लिए एक और अनुकूलन है, बड़े ऑब्जेक्ट हीप एलोकेटर की विशेष संपत्ति है कि यह उन पते पर मेमोरी आवंटित करता है जो 8 से संरेखित होते हैं, जो कि नियमित रूप से उत्पन्न होने वाले आवंटन के विपरीत आवंटित होता है जो केवल 4 से जुड़ा हुआ है। यह संरेखण दोगुने के लिए एक बड़ी बात है। एक गलत संरेखित डबल पढ़ना या लिखना बहुत महंगा है। विचित्र रूप से विरल Microsoft जानकारी में लंबे समय के सरणियों का उल्लेख नहीं है, निश्चित नहीं है कि उसके साथ क्या हो रहा है।

Fwiw, बड़े ऑब्जेक्ट हीप को संकुचित न होने के बारे में बहुत सारे प्रोग्रामर को गुस्सा है। यह हमेशा के लिए शुरू हो जाता है जब वे ऐसे प्रोग्राम लिखते हैं जो पूरे उपलब्ध पते के आधे से अधिक हिस्से का उपभोग करते हैं। एक मेमोरी प्रोफाइलर जैसे टूल का उपयोग करके यह पता लगाने के लिए कि कार्यक्रम में बमबारी क्यों हुई, हालांकि अभी भी बहुत सारी अप्रयुक्त आभासी मेमोरी उपलब्ध थी। इस तरह के एक उपकरण में LOH में छेद दिखाई देता है, स्मृति के अप्रयुक्त विखंडू जहां पहले एक बड़ी वस्तु रहती थी लेकिन कचरा एकत्र हो गया। LOH की ऐसी अपरिहार्य कीमत है, छेद को केवल एक वस्तु के लिए आवंटन द्वारा फिर से उपयोग किया जा सकता है जो आकार में बराबर या छोटा है। वास्तविक समस्या यह मान रही है कि किसी भी कार्यक्रम को किसी भी समय सभी वर्चुअल मेमोरी का उपभोग करने की अनुमति दी जानी चाहिए ।

एक समस्या जो अन्यथा 64-बिट ऑपरेटिंग सिस्टम पर कोड चलाने से पूरी तरह से गायब हो जाती है। 64-बिट प्रक्रिया में वर्चुअल मेमोरी एड्रेस स्पेस के 8 टेराबाइट्स उपलब्ध हैं, 32-बिट प्रक्रिया से अधिक 3 ऑर्डर। आप सिर्फ छेद से बाहर नहीं भाग सकते।

लंबी कहानी छोटी, LOH कोड को अधिक कुशल बनाता है। उपलब्ध वर्चुअल मेमोरी एड्रेस स्पेस कम कुशल उपयोग करने की कीमत पर।


अद्यतन, .NET 4.5.1 अब LOH, GCSettings.LargeObjectHeapCompaction.od संपत्ति को संकुचित करने का समर्थन करता है । कृपया परिणामों से सावधान रहें।


3
@Hans Passant, क्या आप कृपया x64 प्रणाली के बारे में स्पष्ट कर सकते हैं, आपका मतलब है कि यह समस्या पूरी तरह से गायब हो गई है?
जॉनी_ड

LOH के कुछ कार्यान्वयन विवरण समझ में आते हैं, लेकिन कुछ मुझे याद करते हैं। उदाहरण के लिए, मैं समझ सकता है कि कई बड़ी वस्तुओं बनाया है और छोड़ दिया जाता है, यह आम तौर पर उन्हें हटाने के लिए वांछनीय हो सकता है सामूहिक रूप से Gen0 संग्रह में टुकड़ों में से एक जेन 2 संग्रह में है, लेकिन अगर एक बनाता है और छोड़ दिया 22,000 तार की एक सरणी जैसे जो करने के लिए कोई भी बाहरी संदर्भ मौजूद नहीं है, Gen0 और Gen1 कलेक्शन सभी 22,000 तार को "लाइव" होने के लिए मौजूद है, बिना किसी संदर्भ के इस बात का ध्यान रखे कि क्या कोई संदर्भ सरणी में मौजूद है?
सुपरकैट

6
बेशक विखंडन की समस्या सिर्फ x64 पर ही है। इससे पहले कि यह आपके किक करने में आपकी सर्वर प्रक्रिया को चलाने में केवल कुछ दिन लेगा।
लोटहर

1
हम्म, नहीं, परिमाण के 3 आदेशों को कभी कम मत समझना। 4 टेराबाइट के ढेर को इकट्ठा करने में कितना समय लगता है, कुछ ऐसा है जिसे आप उसके करीब पहुंचने से पहले ही खोज सकते हैं।
हंस पासंत

2
@ हंसपसंद आप इस कथन पर विस्तार से बता सकते हैं: "4 टेराबाइट के ढेर को इकट्ठा करने में कितना समय लगता है, कुछ ऐसा है जिसे आप उसके करीब पहुंचने से पहले ही खोज सकते हैं।"
अपेक्षाकृत_ब्रांड

9

यदि ऑब्जेक्ट का आकार कुछ पिन किए गए मूल्य (.NET 1 में 85000 बाइट्स) से अधिक है, तो सीएलआर इसे बड़े ऑब्जेक्ट हीप में डालता है। यह अनुकूलन करता है:

  1. ऑब्जेक्ट आवंटन (छोटी वस्तुओं को बड़ी वस्तुओं के साथ नहीं मिलाया जाता है)
  2. कचरा संग्रह (LOH केवल पूर्ण GC पर एकत्र किया गया)
  3. मेमोरी डीफ़्रैग्मेन्टेशन (LOH को कभी- कभी संकुचित नहीं किया जाता है )

9

स्मॉल ऑब्जेक्ट हीप (एसओएच) और लार्ज ऑब्जेक्ट हीप (एलओएच) का आवश्यक अंतर है, एसओएच में मेमोरी एकत्रित होने पर संकुचित हो जाती है, जबकि एलओएच नहीं, क्योंकि यह लेख दिखाता है। बड़ी वस्तुओं को संकुचित करने से बहुत अधिक लागत आती है। लेख में उदाहरणों के समान, स्मृति में एक बाइट को स्थानांतरित करने के लिए 2 चक्रों की आवश्यकता होती है, फिर 2GHz कंप्यूटर में 8MB ऑब्जेक्ट को 8ms की आवश्यकता होती है, जो एक बड़ी लागत है। बड़ी वस्तुओं (ज्यादातर मामलों में सरणियों) को ध्यान में रखते हुए व्यवहार में काफी आम है, मुझे लगता है यही कारण है कि Microsoft स्मृति में बड़ी वस्तुओं को पिन करता है और एलओएच का प्रस्ताव करता है।

BTW, इस पोस्ट के अनुसार , LOH आमतौर पर स्मृति के टुकड़े की समस्याएं उत्पन्न नहीं करता है।


1
प्रबंधित वस्तुओं में बड़ी मात्रा में डेटा लोड करना आमतौर पर LOH को कॉम्पैक्ट करने के लिए 8ms लागत को बौना करता है। अधिकांश बड़े डेटा अनुप्रयोगों में व्यवहार में, LOH लागत बाकी एप्लिकेशन प्रदर्शन के बगल में तुच्छ है।
शिव

3

प्रिंसिपल यह है कि यह असंभावित (और संभवतः संभवतः खराब डिजाइन) है कि एक प्रक्रिया बहुत सारी जीवित बड़ी वस्तुओं का निर्माण करेगी इसलिए सीएलआर एक अलग ढेर में बड़ी वस्तुओं को आवंटित करता है जिस पर यह नियमित अंतराल पर एक अलग शेड्यूल पर जीसी चलाता है। http://msdn.microsoft.com/en-us/magazine/cc534993.aspx


बड़े ऑब्जेक्ट्स को भी कहते हैं, जनरेशन 2 को जल्दी-जल्दी परफॉर्मेंस मिल सकती है, क्योंकि मेमोरी को कॉम्पेक्ट करने में लंबा समय लगेगा, खासकर अगर छोटी राशि से मुक्ति मिली हो और बड़ी वस्तुओं को नए स्थान पर कॉपी करना पड़े। वर्तमान LOH प्रदर्शन कारणों से संकुचित नहीं है।
क्रिस्टोफर Currens

मुझे लगता है कि यह केवल खराब डिजाइन है क्योंकि जीसी इसे अच्छी तरह से नहीं संभालता है।
कोडइन्चोस

@CodeInChaos जाहिर है, .NET 4.5 में
क्रिश्चियन

1
@CodeInChaos: जबकि यह सिस्टम के लिए प्रतीक्षा कर सकता है कि एक जीन 2 संग्रह तक प्रतीक्षा करने के लिए सिस्टम को कम से कम एलओएच ऑब्जेक्ट्स से मेमोरी को पुनः प्राप्त करने का प्रयास करने से पहले, मैं एलओएच ऑब्जेक्ट्स (और किसी भी ऑब्जेक्ट के लिए) को घोषित करने के लिए कोई प्रदर्शन लाभ नहीं देख सकता। संदर्भ) बिना gen0 और gen1 संग्रह के दौरान बिना शर्त के रहते हैं। क्या कुछ अनुकूलन हैं जो इस तरह की धारणा से संभव हैं?
सुपरकैट

@supercat मैंने Myles McDonnell द्वारा उल्लिखित लिंक को देखा। मेरी समझ यह है: 1. LOH संग्रह एक जनरल 2 GC में होता है। 2. LOH संग्रह में संघनन शामिल नहीं है (उस समय तक जब लेख लिखा गया था)। इसके बजाय, यह मृत वस्तुओं को पुन: प्रयोज्य के रूप में चिह्नित करेगा और ये छेद भविष्य में एलओएच आवंटन की सेवा करेंगे यदि पर्याप्त बड़ा हो। बिंदु 1 के कारण, यह विचार करते हुए कि एक जीन 2 GC धीमा होगा यदि जीन 2 में कई ऑब्जेक्ट हैं, तो मुझे लगता है कि इस मामले में जितना संभव हो उतना LOH का उपयोग करने से बचें।
रॉबी फैन

0

मैं सीएलआर का विशेषज्ञ नहीं हूं, लेकिन मुझे लगता है कि बड़ी वस्तुओं के लिए एक समर्पित ढेर होने से मौजूदा पीढ़ीगत ढेर के अनावश्यक जीसी स्वीप को रोका जा सकता है। किसी बड़ी वस्तु को आवंटित करने के लिए महत्वपूर्ण मात्रा में सन्निहित मुक्त स्मृति की आवश्यकता होती है । जेनरल हीप्स में बिखरे हुए "छेद" से प्रदान करने के लिए, आपको बार-बार कम्पार्टमेंट (जो केवल जीसी साइकिल के साथ किया जाता है) की आवश्यकता होगी।

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