2011-12-19 22 views
51

आज मेरे आवेदन ने आज OutOfMemoryException फेंक दिया। मेरे लिए यह हमेशा लगभग असंभव था क्योंकि मेरे पास 4 जीबी रैम और वर्चुअल मेमोरी भी है। त्रुटि तब हुई जब मैंने एक मौजूदा सूची को एक नई सूची में जोड़ने का प्रयास किया।सी #: मेमोरी अपवाद से बाहर

List<Vehicle> vList = new List<Vehicle>(selectedVehicles); 

मेरी समझ के लिए यहां बहुत अधिक स्मृति आवंटित नहीं है क्योंकि वाहनों की मेरी नई सूची में स्मृति के अंदर पहले से मौजूद होना चाहिए। मुझे Vehicle स्वीकार करना बहुत जटिल वर्ग है और मैंने एक बार में नई सूची में लगभग 50,000 आइटम जोड़ने की कोशिश की। लेकिन चूंकि एप्लिकेशन में सभी Vehicle एस डेटाबेस से आते हैं जो आकार में केवल 200 एमबी है: मुझे नहीं पता कि इस बिंदु पर OutOfMemoryException का कारण क्या हो सकता है।

+7

'selectedVehicles' का मूल्य (और प्रकार) क्या है? – harold

+1

जब 'आउटऑफमेमरी अपवाद' फेंक दिया गया था, तो क्या आपने डीबगर के साथ प्रक्रिया को संलग्न किया था और देखें कि समस्या क्या हो सकती है? वस्तुएं कितनी बड़ी थीं? .NET Framework में ऑब्जेक्ट आकार के लिए 2 जीबी की हार्ड सीमा है, ढांचे से खपत ओवरहेड कम से कम। –

+1

वाहन संभवतः कक्षा के बजाय एक संरचना है? –

उत्तर

57

दो अंक:

  1. आप एक 32 बिट Windows चला रहे हैं, तो आप सब 4GB सुलभ, केवल 2GB नहीं होगा।
  2. यह न भूलें कि List का अंतर्निहित कार्यान्वयन एक सरणी है। यदि आपकी याददाश्त बहुत कम हो गई है, तो आपके List आवंटित करने के लिए पर्याप्त संगत स्थान नहीं हो सकता है, भले ही आपके पास कुल मिलाकर निःशुल्क स्मृति हो।
+21

आपके पास 64-बिट विंडोज़ में केवल 2 जीबी उपलब्ध है। यह 32-बिट एड्रेस स्पेस के न केवल .NET Framework की एक सीमा है। –

+0

+1 बिंदु 2 के लिए। वह एक खंडित सूची लिखने का प्रयास कर सकता है। –

+22

@ कोडीग्रे यह 2 जीबी प्रति ऑब्जेक्ट (सरणी) होगा, 2 जीबी कुल नहीं। –

10

आपके आवेदन में स्मृति की तुलना में डेटाबेस में संग्रहीत डेटा बहुत अलग है।

वहाँ एक तरीका है अपनी वस्तु की सटीक आकार पाने के लिए नहीं है, लेकिन आप यह कर सकता है: के बाद वस्तुओं की एक निश्चित राशि लोड हो जाने

GC.GetTotalMemory() 

और देखो कितना अपनी स्मृति आप के रूप में बदल रहा है सूची लोड करें।

यदि यह सूची है जो अत्यधिक स्मृति उपयोग कर रही है तो हम इसे कम करने के तरीकों को देख सकते हैं। इस तरह आप 50,000 ऑब्जेक्ट्स को पहले मेमोरी में एक बार मेमोरी में लोड क्यों करना चाहते हैं। डीबी को कॉल करने के लिए सबसे अच्छा नहीं होगा क्योंकि आपको उनकी आवश्यकता है?

यदि आप यहां एक नज़र डालें: http://www.dotnetperls.com/array-memory आप यह भी देखेंगे कि .NET में ऑब्जेक्ट्स उनके वास्तविक डेटा से अधिक हैं। एक जेनेरिक सूची एक सरणी की तुलना में एक स्मृति हॉग का भी अधिक है। यदि आपके पास अपनी ऑब्जेक्ट के अंदर एक सामान्य सूची है तो यह और भी तेज़ी से बढ़ेगी।

7

OutOfMemoryException (32-बिट मशीन) बस के रूप में अक्सर विखंडन के बारे में है के रूप में स्मृति पर वास्तविक कठिन सीमा - आप इस बारे में बहुत सारे मिल जाएगा, लेकिन यहाँ मेरा पहला गूगल संक्षेप में चर्चा मारा है: http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx। (@ एंथनी पेग्राम ऊपर उनकी टिप्पणी में एक ही समस्या का जिक्र कर रहा है)।

यानी, एक अन्य संभावना के ऊपर अपने कोड के लिए मन में आता है है: आप सूची के लिए "IEnumerable" निर्माता का उपयोग कर रहे हैं, आप मई नहीं के आकार के रूप में वस्तु किसी भी संकेत देकर संग्रह जो आप सूची निर्माता को पास कर रहे हैं। यदि आप जिस वस्तु को पारित कर रहे हैं वह संग्रह नहीं है (ICollection इंटरफ़ेस को लागू नहीं करता है), तो पीछे के दृश्यों को सूची कार्यान्वयन को कई (या कई) बार बढ़ने की आवश्यकता होगी, हर बार एक बहुत छोटा सरणी जो कचरा इकट्ठा करने की जरूरत है। कचरा कलेक्टर संभवतः उन त्याग किए गए सरणी को पर्याप्त तेज़ नहीं करेगा, और आपको अपनी त्रुटि मिल जाएगी।

इस के लिए सबसे सरल ठीक List(int capacity) निर्माता का उपयोग करने के क्या समर्थन सरणी आकार आवंटित करने के लिए (भले ही आप अनुमान लगा रहे हैं और सिर्फ उदाहरण के लिए "50000" अनुमान लगा) ढांचे को बताने के लिए किया जाएगा, और उसके बाद के लिए AddRange(IEnumerable collection) विधि का उपयोग वास्तव में अपनी सूची populate।

तो, सबसे सरल "ठीक करें" अगर मैं सही हूँ: की जगह

List<Vehicle> vList = new List<Vehicle>(selectedVehicles); 

साथ

List<Vehicle> vList = new List<Vehicle>(50000); 
vList.AddRange(selectedVehicles); 

सभी अन्य टिप्पणी और जवाब अभी भी समग्र डिजाइन निर्णय के मामले में लागू होते हैं - लेकिन इस एक त्वरित फिक्स हो सकता है।

नोट (जैसा कि @ एलेक्स नीचे टिप्पणी की गई है), यह केवल एक मुद्दा है यदि selectedVehicles आईसीओलेक्शन नहीं है।

+3

यदि selecyedVehicles एक संग्रह है, तो कन्स्ट्रक्टर आवंटित करेगा सही सरणी आकार। AddRange के माध्यम से जाने की जरूरत नहीं है। – Alex

3

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

58

.Net4.5 किसी भी अधिक वस्तुओं के लिए एक 2GB सीमा नहीं है चाहता हूँ। App.config

<runtime> 
    <gcAllowVeryLargeObjects enabled="true" />  
</runtime> 

को यह पंक्तियां जोड़ें और यह OutOfMemoryException

प्राप्त किए बिना बहुत बड़ी वस्तुओं को बनाने के कृपया ध्यान दें यह 64 ओएस पर ही काम करेगा संभव हो जाएगा!

+0

अच्छी तरह से किया गया। यह मेरे लिए काम करता था, नोटिंग को बिल्ड लक्ष्य को x64 में बदलना पड़ा था। –

+0

एएसपी.NET 4.5 पर भी लागू होता है? स्थानीय रिपोर्ट का उपयोग करके, * मेरा ऐप v1 (asp.net 3.5 - clr 2.0 - क्लासिक) * काम करता है *** ठीक ***, लेकिन मेरा ऐप v2 (asp.net 4.5, clr 4.0, क्लासिक) उत्पन्न होता है *** OutOfMemoryException त्रुटि ***, एक ही आईआईएस सर्वर_ – Kiquenet

67

3 साल पुराना विषय, लेकिन मुझे एक और कामकाजी समाधान मिला।

हम कहा: क्या आप वाकई पर्याप्त मुक्त स्मृति है, 64 बिट ओएस चल रहा है और अभी भी अपवाद हो रही हैं, तो अपने परियोजना संपत्तियों में यह विकल्प सेट करने के लिए सुनिश्चित enter image description here

+1

में कोई छवि मौजूद नहीं है – TheGameiswar

4

मेरे विकास टीम इस स्थिति का समाधान हो सकता है निम्नलिखित पोस्ट-बिल्ड स्क्रिप्ट .exe प्रोजेक्ट में और फिर संकलित, लक्ष्य को x86 पर सेट करना और 1.5 जीबी तक बढ़ाना और x64 प्लेटफ़ॉर्म लक्ष्य 3.2 जीबी का उपयोग करके स्मृति को बढ़ा रहा है। हमारा आवेदन 32 बिट है।

संबंधित URL:

स्क्रिप्ट:

if exist "$(DevEnvDir)..\tools\vsvars32.bat" (
    call "$(DevEnvDir)..\tools\vsvars32.bat" 
    editbin /largeaddressaware "$(TargetPath)" 
) 
संबंधित मुद्दे