2012-01-03 15 views
6

मुझे एक समस्या है जो मुझे कुछ दिनों के लिए परेशान कर रही है। मैंने Google को समस्या का प्रयास करने की कोशिश की है, लेकिन अभी तक कोई समाधान नहीं मिला है, एक ही समस्या वाले एक व्यक्ति भी नहीं।सी # System.Buffer.BlockCopy मेमोरी समस्या?

ऐसा लगता है कि सी # विधि सिस्टम.बफर.ब्लॉककॉपी आपको कुछ प्रकार के मेमोरी भूत के साथ छोड़ देता है। मेरे पास उदाहरण के लिए इस विधि है:

private float[,] readFloatArray2 (byte[] b) { 
    int floatSize = sizeof(float); 
    float[,] v = new float[2, (b.Length/2)/floatSize]; 
    System.Buffer.BlockCopy(b, 0, v, 0, b.Length); 

    return v; 
} 

एक बाइट सरणी को 2 डी फ्लोट सरणी में परिवर्तित करने के लिए। डेटा पहले एक स्ट्रीम से पढ़ा जाता है। मैंने सिस्टम.बफर.ब्लॉककॉपी विधि होने की समस्या को हल किया है।

यदि मैं ब्लॉककॉपी कमांड को हटा देता हूं, तो एप्लिकेशन द्वारा उपयोग की जाने वाली मेमोरी आधा आकार होगी। इसका मतलब है कि यह मेरी गलती नहीं है कि बाइट सरणी अभी भी जीवित है। क्योंकि BlockCopy कमांड के बिना, बाइट सरणी ठीक से मर जाती है। फ्लोट सरणी वैसे भी बनाई जाती है (कॉपी की गई जानकारी के साथ या उसके बिना)।

मुझे यकीन नहीं है कि यह ब्लॉककॉपी कमांड या जीसी की समस्या है क्योंकि मैंने System.GC.Collect() को कॉल करने का भी प्रयास किया है; ब्लॉककॉपी के बाद और फिर यह पूरी तरह से काम करता है (मुझे पता है कि आपको यह नहीं करना चाहिए ... यही कारण है कि मैं यहां सलाह देने के लिए कह रहा हूं)।

मैं भी पूछना परेशान नहीं करता, लेकिन इस मुद्दे में कई सौ मेग शामिल हैं।

स्मृति समस्याओं के अलावा, विधि पूरी तरह ठीक काम करती है। क्या किसी को पता है कि स्मृति समस्या का कारण क्या है?

बधाई और अग्रिम धन्यवाद ओली

ps: मैं दृश्य स्टूडियो 2010 प्रो और Win7 के साथ .NET4.0 उपयोग कर रहा हूँ ... पता नहीं है कि क्या यह प्रासंगिक है या नहीं।

+2

यदि आप कहते हैं कि स्मृति 'जीसी.कोलेक्ट' द्वारा ठीक से एकत्र की जाती है तो सब कुछ ठीक है। समय बी आने पर 'बी' * * अंततः एक सामान्य जीसी द्वारा एकत्र किया जाएगा। –

+0

यदि आप ऑडियो डेटा पर काम कर रहे हैं, तो मैं 'फ्लोट [लेन] [चैनलकाउंट]' फॉर्म की एक जंजीर सरणी का उपयोग करूंगा। इस तरह आप चैनलों को अलग से इलाज कर सकते हैं, जो कभी-कभी उपयोगी होता है। – CodesInChaos

+1

"फ्लोट सरणी वैसे भी बनाई जाती है" केवल आधे सच। इसे अभी तक भौतिक स्मृति की आवश्यकता नहीं है। मेमोरी पेज जो सभी 0 हैं और कभी भी लिखे गए नहीं हैं, विंडोज मेमोरी मैनेजर द्वारा अनुकूलित किए गए हैं। – CodesInChaos

उत्तर

1

BlockCopy ने .NET कार्यान्वयन को प्रबंधित नहीं किया है। आंतरिक रूप से, यह बाहरी जीत एपीआई का आह्वान करता है।

[SecuritySafeCritical] 
public static extern void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count); 
+0

ठीक है ... और इस समस्या से निपटने के लिए कैसे? आपकी क्या सलाह है? –

+0

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

1

Buffer.BlockCopy इंडेक्स-आधारित के बजाय बाइट-आधारित है। मैं आपको Array.Copy का उपयोग करने का सुझाव दूंगा जो मूल रूप से वही काम करता है। ब्लॉककॉपी बस थोड़ा तेज है।

आपको लगता है कि

static float[] ConvertByteArrayToFloat(byte[] bytes) 
{ 
    if(bytes == null) 
     throw new ArgumentNullException("bytes"); 

    if(bytes.Length % 4 != 0) 
     throw new ArgumentException 
       ("bytes does not represent a sequence of floats"); 

    return Enumerable.Range(0, bytes.Length/4) 
        .Select(i => BitConverter.ToSingle(bytes, i * 4)) 
        .ToArray(); 
} 
+0

लेकिन ऐरे। कॉपी विभिन्न डेटाटाइप के साथ काम नहीं करता है। मैं इसे बाइट [] से फ्लोट करने के लिए उपयोग नहीं कर सकता [,]। –

+0

मैंने अपना उत्तर –

+0

हाँ संपादित किया है ... ठीक है ... यह अच्छा है लेकिन मेरे पास 2 डी फ्लोट सरणी (फ्लोट [,]) के लिए 1 डी बाइट सरणी है। लेकिन आपका सुझाव अच्छा है। मुझे यह नहीं पता था। (अब 4 महीने के लिए सी # में कोडिंग) –

2

मैं इस समस्या का पता चला है System.Buffer.BlockCopy विधि के लिए के लिए कम-से-[] first.Have एक नज़र फ्लोट करने के लिए बाइट [] बदलना होगा। अगर मैं BlockCopy कमांड को हटा देता हूं, तो एप्लिकेशन द्वारा उपयोग की जाने वाली मेमोरी आधा आकार होगी। इसका मतलब है कि यह मेरी गलती नहीं है कि बाइट सरणी अभी भी जीवित है। क्योंकि BlockCopy कमांड के बिना, बाइट सरणी ठीक से मर जाती है।

मैं उस निष्कर्ष से असहमत हूं। मैं कई चरणों देखें:

  1. बाइट सरणी मौजूद है और डेटा
  2. आप नाव सरणी का आवंटन से भर जाता है, लेकिन यह डेटा के साथ अभी तक भरा नहीं है।
  3. आप डेटा
  4. बाइट सरणी अब संदर्भित नहीं है के साथ नाव सरणी को भरने, लेकिन अभी तक एकत्र नहीं किया गया है
  5. बाइट सरणी एकत्र किया गया है।

बाइट सरणी का लाइव BlockCopy से प्रभावित नहीं है।

चरण 2 रिजर्व और वर्चुअल मेमोरी करता है। तो इस चरण में प्रतिबद्धता का आकार बढ़ता है। लेकिन चूंकि सरणी की सामग्री को कभी भी लिखा नहीं गया है, और इसमें 00 बाइट्स शामिल हैं, विंडोज़ मेमोरी मैनेजर इसके लिए कोई भौतिक स्मृति आवंटित नहीं करता है। यह सिर्फ नोट करता है कि इन पृष्ठों में पूरी तरह से 00 एस शामिल हैं।

फ्लोट सरणी के लिए भौतिक स्मृति केवल चरण 3 में आवंटित हो जाती है। यदि आप एक लूप जोड़ते हैं जो सरणी में प्रत्येक फ़ील्ड को प्रारंभ करता है तो आपको वही प्रभाव मिल जाएगा।

  1. पुन: उपयोग बफ़र्स:


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

  2. यदि आप ऑडियो डेटा (संभवतः लगता है) के साथ काम कर रहे हैं, तो मैं एक ठोस 2 डी सरणी का उपयोग नहीं करता। मैं इसके बजाय सरणी की एक सरणी का उपयोग करेंगे। जहां आंतरिक सरणी एक बफर में नमूने का प्रतिनिधित्व करती है, और बाहरी सरणी बफर का प्रतिनिधित्व करती है। इसमें दो फायदे हैं:

    • आप आसानी से कोड लिख सकते हैं जो केवल एक चैनल पर चल रहा है।
    • सॉलिड 2 डी एरे इंडेक्स में धीमे हैं, इसलिए यह अक्सर तेज़ होता है।
  3. क्या आप वास्तव में एक बार में सभी डेटा पढ़ना चाहते हैं? मैं कुछ किलोबाइट्स के टुकड़ों में पढ़ता था।
+0

मैं जैव सूचना विज्ञान हूं इसलिए, मैं ऑडियो फ़ाइलों के साथ काम नहीं करता हूं। एमएस स्पेक्ट्रा के साथ अधिक पसंद है। मुझे प्रसंस्करण के लिए WHOLE डेटा की आवश्यकता है और इसलिए डिजाइन सुझाव 1. और 2. कोई विकल्प नहीं है (चरण 1 कोई विकल्प नहीं है क्योंकि पठित बाइट्स की लंबाई नाटकीय रूप से भिन्न होती है (32 बाइट्स से> 10.000.000 तक)। डिज़ाइन सुझाव 3 भी एक विकल्प नहीं है क्योंकि मुझे विभिन्न पहलुओं को हाइलाइट करने के लिए डेटा के विभिन्न हिस्सों को एक से अधिक बार संसाधित करना होगा। इसलिए फ्लाई पर सब कुछ पुनः लोड करना संभव नहीं है क्योंकि मुझे प्रक्रिया के अंत तक जानकारी के पूरे सेट की आवश्यकता है। लेकिन वैसे भी धन्यवाद :) –

+0

ओह ... और सुझाव 3 के लिए, मैं एक बार में सभी को नहीं पढ़ता। मैंने स्पेक्ट्र्रा-वार पढ़ा। और एक स्पेक्ट्रा आकार 32 बी से> 10 एमबी तक भिन्न हो सकता है। और मेरे पास पढ़ने के लिए लगभग 80,000 स्पेक्ट्रा है। प्रसंस्करण के लिए उनमें से प्रत्येक एक आवश्यक है। –

1

मैं काफी यकीन नहीं अगर यह या BlockCopy आदेश की एक समस्या जीसी क्योंकि मैं भी System.GC.Collect() कॉल करने के लिए कोशिश की है है कर रहा हूँ; ब्लॉककॉपी के बाद और फिर यह पूरी तरह से काम करता है (मुझे पता है कि आपको यह नहीं करना चाहिए ... यही कारण है कि मैं यहां सलाह देने के लिए कह रहा हूं)। मैं यह भी परेशान नहीं करता कि क्या यह कई हंड्रेट एमबी के बारे में नहीं है, जिसके बारे में हम बात कर रहे हैं।

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

ऐसे समय होते हैं जब GC.Collect() पर कॉल करना वास्तविक कार्यक्रम में समझ में आता है, और यह उनमें से एक हो सकता है, इसलिए यदि ऐसा करना "पूरी तरह से काम करता है", तो मैं इसके बारे में ज्यादा चिंता नहीं करता क्योंकि यह सर्वोत्तम- कोड का 99.9% अभ्यास करें। एक कठिन और तेज़ नियम के बजाय यह "सर्वोत्तम अभ्यास" का कारण यह है कि कभी-कभी हम 0.1% मामले में होते हैं और आमतौर पर सबसे अच्छा अभ्यास क्या सबसे अच्छा अभ्यास नहीं है।

इसके अलावा, यदि आप समय से पहले सरणी के अधिकतम आकार (या केवल स्रोत बाइट एरे के) में विफल होने की भविष्यवाणी कर सकते हैं, तो CodeInChaos का पहला दृष्टिकोण काम कर सकता है। यह वास्तव में 32,000 प्रोसेस करने के लिए 10,000,000 बाइट्स का उपयोग करने में चोट नहीं पहुंचाता है, जब तक कि आप वास्तव में उस 10,000,000 का उपयोग करेंगे। प्रक्रिया के जीवनकाल में एक बहुत ही वास्तविक बचत के लिए 10,000,000 का पुन: उपयोग करना।