2009-07-09 18 views
16

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

उदाहरण: 5 आवंटित 96 एमबी सरणी (200x200x200, प्रत्येक प्रविष्टि में डेटा के 12 बाइट) हैं और कार्यक्रम को उन्हें 210x210x210 (111MB) के साथ बदलने की आवश्यकता है। यह इस तरह से करता है:

array1 = new Vector3[210,210,210]; 

जहां array1-array5 पहले इस्तेमाल किए गए समान फ़ील्ड हैं। इसे पुरानी सरणी को कचरे के संग्रह के लिए उम्मीदवारों के रूप में सेट करना चाहिए, लेकिन प्रतीत होता है कि जीसी जल्दी से पर्याप्त कार्य नहीं करता है और नए लोगों को आवंटित करने से पहले आवंटित पुराने सरणी छोड़ देता है - जो ओओएम का कारण बनता है - जबकि यदि वे नए आवंटन से पहले मुक्त हो जाते हैं तो अंतरिक्ष होना चाहिए पर्याप्त।

क्या मैं के लिए देख रहा हूँ इस तरह कुछ करने के लिए एक तरीका है:

GC.Collect(array1) // this would set the reference to null and free the memory 
array1 = new Vector3[210,210,210]; 

मुझे यकीन है कि नहीं कर रहा हूँ अगर एक पूर्ण कचरा collecion एक अच्छा विचार होगा कि कोड के बाद से हो सकता है (कुछ स्थितियों में) काफी बार निष्पादित करने की आवश्यकता है।

क्या ऐसा करने का कोई उचित तरीका है?

+2

यह वास्तव में अजीब लगता है कि इससे ओओएम अपवाद होगा। क्या आपके पास कुछ नमूना कोड है जो समस्या का प्रदर्शन करता है? – aquinas

+0

यह एक बड़े पैमाने पर (अभी भी अप्रकाशित) कार्यक्रम का हिस्सा है और दुर्भाग्य से मैं केवल वास्तविक कोड के छोटे स्निपेट पोस्ट कर सकता हूं, जो कि संकलन योग्य होने के लिए पर्याप्त नहीं है। –

+0

आपकी समस्या मेमोरी प्रबंधन नहीं है, लेकिन आप बहुत बड़े सरणी का उपयोग कर रहे हैं। आपको लगता है कि आपको उन बड़े सरणीओं को पहली जगह क्यों चाहिए? आप उनके लिए क्या उपयोग कर रहे हैं? – Guffa

उत्तर

14

यह मूल प्रश्न, "कैसे जी सी 'के लिए मजबूर करने के लिए एक सटीक जवाब नहीं है, फिर भी मुझे लगता है कि आप अपने मुद्दे का पुनर्परीक्षण करने में मदद मिलेगी।

अपनी टिप्पणी देखने के बाद,

  • जीसी डालकर।इकट्ठा(); ऐसा लगता है, यह सोचता है कि यह अभी भी पूरी तरह से समस्या का समाधान नहीं करता है - किसी कारण से प्रोग्राम लगभग तब भी दुर्घटनाग्रस्त हो जाता है जब लगभग 1.3 जीबी आवंटित किया जाता है (मैं सिस्टम.जीसी.गेटटॉटलमेमरी (झूठी) का उपयोग कर रहा हूं; वास्तविक राशि आवंटित करने के लिए)।

मुझे लगता है कि आप स्मृति विखंडन हो सकता है। यदि ऑब्जेक्ट बड़ा है (अगर मुझे सही याद है, तो नेट 2.0 सीएलआर के तहत 85000 बाइट्स, मुझे नहीं पता कि यह बदल गया है या नहीं), ऑब्जेक्ट को विशेष ढेर, बड़े ऑब्जेक्ट हीप (LOH) में आवंटित किया जाएगा। जीसी LOH में पहुंचने योग्य वस्तुओं द्वारा उपयोग की जाने वाली स्मृति को पुनः प्राप्त करता है, फिर भी, यह LOH में कॉम्पैक्शन, निष्पादन नहीं करता है क्योंकि यह प्रदर्शन के कारण अन्य ढेर (gen0, gen1, और gen2) के साथ करता है।

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

मैं इस समय दो कामकाज सोच सकता हूं।

  1. ले जाएँ 64-बिट मशीन/ओएस और इसका लाभ उठाने के :) (सबसे आसान है, लेकिन संभवतः सबसे मुश्किल के रूप में अच्छी तरह से अपने संसाधन की कमी के आधार पर)
  2. आप # 1 ऐसा नहीं कर सकते हैं, तो एक आवंटित करने के लिए प्रयास करने के लिए पहले स्मृति की विशाल चक और उनका उपयोग करें (विखंडन से बचने के लिए इसे एक छोटे सरणी में घुमाने के लिए कुछ सहायक वर्ग लिखने की आवश्यकता हो सकती है, जो वास्तव में एक बड़े सरणी में रहता है)। यह थोड़ा सा मदद कर सकता है, फिर भी, यह इस मुद्दे को पूरी तरह से हल नहीं कर सकता है और आपको जटिलता से निपटना पड़ सकता है।
+2

या एक जंजीर सरणी का उपयोग करने के लिए स्विच करें - वेक्टर 3 [210] [210] [210], जो आवंटन को विभाजित करेगा और स्मृति के एक बड़े बड़े ब्लॉक का उपयोग नहीं करेगा – thecoop

+0

ऐसा लगता है कि समस्या वास्तव में इस विखंडन मुद्दे के कारण होती है। दुर्भाग्य से मैं प्रोग्राम को 64 बिट पर पोर्ट नहीं कर सकता क्योंकि XNA केवल 32 बिट का समर्थन करता है। स्टार्टअप पर एक बड़ी सरणी आवंटित करना शायद छोटे मामलों (100x100x100 के तहत) और अतिरिक्त काम करने के लिए अतिरिक्त काम पर अतिरिक्त मेमोरी के लायक नहीं होगा। मैंने गणित किया और यहां तक ​​कि यदि मैं अधिकतम 2 जीबी का उपयोग कर सकता हूं तो अधिकतम वॉल्यूम आकार में सुधार पर्याप्त नहीं होगा (लगभग 200^3 से 300^3 तक) बनाने के लिए एक हैक खोजने/कार्यान्वित करने की परेशानी के माध्यम से यह कम से कम अभी तक काम नहीं करता है। उन सभी को धन्यवाद जिन्होंने मदद करने की कोशिश की! –

7

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

array1 = null; 
GC.Collect(); 
array1 = new Vector3[210,210,210]; 
+2

नहीं, आपको जीसी को कॉल नहीं करना चाहिए। बिल्कुल चयन करें। सबसे अच्छा समाधान है कि नई सरणी आवंटित होने से पहले संदर्भ को हटा दें और कचरा कलेक्टर बिना हस्तक्षेप किए काम करें। – Guffa

+5

यदि रनटाइम आवंटन के लिए पर्याप्त मेमोरी नहीं पा रहा है तो यह संग्रह को ट्रिगर करेगा, इसलिए GC.Collect को स्पष्ट कॉल की आवश्यकता नहीं है। –

+3

जॉन डो ने सभी के बाद * फोर्सिंग * कचरा संग्रह के बारे में पूछा था। – icelava

1

वे एकत्र नहीं किया जा सकता है हो रही है, क्योंकि वे कहीं संदर्भित आप अपेक्षा नहीं कर रहे जा रहा है।

एक परीक्षण के रूप में, अपने संदर्भों को WeakReferences पर बदलने का प्रयास करें और देखें कि क्या यह आपकी ओओएम समस्या का समाधान करता है। यदि ऐसा नहीं होता है तो आप उन्हें कहीं और संदर्भित कर रहे हैं।

+0

वे केवल उस कोड में उपयोग किए जाते हैं जो उन्हें उत्पन्न करता है और उस कोड में जो डेटा का उपयोग करता है (XNA VertexBuffer, वॉल्यूम को प्रस्तुत करने के लिए उपयोग किया जाता है) इसलिए मुझे नहीं लगता कि कुछ और उनका संदर्भ देता है। मैंने कभी पहले वीक संदर्भों का उपयोग नहीं किया है, लेकिन उस लेख से मुझे लगता है कि बाकी निष्पादन के दौरान उन्हें हटा दिया जा सकता है - और यह शेष कोड के लिए गंभीर समस्या पैदा करेगा। –

2

अगर मैं तुम्हें समस्या सट्टा करने के लिए किया था वास्तव में है कि आप Vector3 [200,200,200] से एक Vector3 [210,210,210] लेकिन करने जा रहे हैं नहीं है कि सबसे अधिक संभावना है कि आप इसे पहले भी ऐसी ही पिछले चरण है:

 
i.e. 
    // first you have 
    Vector3[10,10,10]; 
    // then 
    Vector3[20,20,20]; 
    // then maybe 
    Vector3[30,30,30]; 
    // .. and so on .. 
    // ... 
    // then 
    Vector3[200,200,200]; 
    // and eventually you try 
    Vector3[210,210,210] // and you get an OutOfMemoryException.. 

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

तो, इसके बाद के संस्करण के बजाय, कुछ इस तरह है:

// first start with an arbitrary size 
Vector3[64,64,64]; 
// then double that 
Vector3[128,128,128]; 
// and then.. so in thee steps you go to where otherwise 
// it would have taken you 20.. 
Vector3[256,256,256]; 
+0

ध्यान दें कि संग्रहित कक्षाओं में से कुछ आपके लिए यह करेंगे। – Brian

+0

मैं सहमत हूं, इस तरह के सरणी को लगातार आवंटित करना सिर्फ ओओएम त्रुटियों के लिए भीख मांग रहा है। –

+0

असल में सरणी का "आकार बदलना" उपयोगकर्ता इनपुट द्वारा ट्रिगर किया जाता है और अनुमानित नहीं है (पूरी तरह से मैं मैन्युअल रूप से इसे परीक्षण करने के चरणों में बढ़ा रहा हूं)। ओवरलैकोटिंग एक विकल्प नहीं है, जो वास्तव में इसे पहले दुर्घटनाग्रस्त कर देगा, कुल आकार को घनत्व में बढ़ाएगा। –

0

एक OutOfMemory अपवाद आंतरिक रूप से एक बार स्वचालित रूप से एक जीसी चक्र ट्रिगर करता है और वास्तव में आपके कोड में अपवाद फेंकने से पहले आवंटन का प्रयास करता है। आउटऑफमेमरी अपवाद होने का एकमात्र तरीका यह है कि यदि आप बहुत अधिक स्मृति के संदर्भ रखते हैं। जैसे ही आप उन्हें शून्य से निर्दिष्ट कर सकते हैं संदर्भों को साफ़ करें।

4

क्या यह सिर्फ बड़ी वस्तु ढेर विखंडन नहीं है? ऑब्जेक्ट्स> 85,000 बाइट बड़े ऑब्जेक्ट ढेर पर आवंटित किए जाते हैं। जीसी इस ढेर में जगह मुक्त करता है लेकिन शेष वस्तुओं को कभी भी कॉम्पैक्ट नहीं करता है। इसके परिणामस्वरूप बड़ी वस्तु को सफलतापूर्वक आवंटित करने के लिए अपर्याप्त संगत स्मृति हो सकती है।

एलन।

0

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

एक दांतेदार सरणी के रूप में यह आवंटन का प्रयास करें - Vector3 [210] [210] [210] - जो इसके बजाए एक ही ब्लॉक के रूप में की तुलना में स्मृति के आसपास सरणियों फैलता है, और देखते हैं कि अगर मामले को बेहतर बनाता है

1

मैं समझता हूँ कि तुम क्या तत्काल कचरा संग्रह के लिए करने और धक्का देने की कोशिश कर रहे हैं शायद सही दृष्टिकोण नहीं है (क्योंकि जीसी अपने तरीकों से सूक्ष्म है और क्रोध के लिए जल्दी है)।

उस ने कहा, यदि आप चाहते हैं कि कार्यक्षमता है, तो इसे क्यों नहीं बनाएं?

public static void Collect(ref object o) 
{ 
    o = null; 
    GC.Collect(); 
} 
+0

यह कोई काम नहीं करता है। आप ऑब्जेक्ट ओ पॉइंट ऑब्जेक्ट के संदर्भ की प्रतिलिपि बना रहे हैं, जो मूल ऑब्जेक्ट ओ के लिए कुछ भी नहीं करता है। –

+0

आप समझते हैं कि यदि मैं एक रेफरी वैरिएबल को साइड-इफेक्ट करता हूं, तो यह कॉलर की प्रति भी बदलता है, है ना? – plinth

+0

मेरे पास +1 है, यह कोड वास्तव में मूल चर को शून्य पर इंगित करेगा क्योंकि यह मूल चर के सूचक को संदर्भ द्वारा संशोधित कर रहा है। –

9

लगता है कि आप LOH (बड़े ऑब्जेक्ट ढेर) विखंडन मुद्दे में भाग चुके हैं।

Large Object Heap

CLR Inside Out Large Object Heap Uncovered

आप आप कैसे एसओएस का उपयोग करने के लोह का निरीक्षण करने का एक उदाहरण के लिए एसओएस

चेक इस question का उपयोग कर लोह विखंडन समस्या है तो इस बात की जाँच कर सकते हैं।

0

जॉन, ऑब्जेक्ट्स बनाना> 85000 बाइट्स ऑब्जेक्ट को बड़े ऑब्जेक्ट ढेर में समाप्त कर देगा। बड़ी वस्तु ढेर कभी संकुचित नहीं होती है, इसके बजाय मुक्त स्थान दोबारा उपयोग किया जाता है। इसका मतलब है कि यदि आप हर बार बड़े सरणी आवंटित कर रहे हैं, तो आप उन परिस्थितियों में समाप्त हो सकते हैं जहां LOH खंडित है, इसलिए ओओएम।

आप ओओएम के बिंदु पर डीबगर के साथ तोड़कर और डंप प्राप्त करने के मामले में यह पुष्टि कर सकते हैं कि एक कनेक्ट बग (http://connect.microsoft.com) के माध्यम से एमएस को इस डंप को सबमिट करना एक महान शुरुआत होगी।

मैं आपको आश्वस्त कर सकता हूं कि जीसी आपको आवंटन अनुरोध को पूरा करने की कोशिश करने वाली सही चीज़ करेगा, इसमें नए आवंटन अनुरोधों को पूरा करने के लिए पुराने कचरे को साफ करने के लिए जीसी को लात मारना शामिल है।

मुझे नहीं पता कि स्टैक ओवरफ्लो पर मेमोरी डंप को साझा करने की नीति क्या है, लेकिन मुझे आपकी समस्या को और समझने में एक खुशी होगी।

संबंधित मुद्दे