2009-07-04 10 views
7

प्रतिबिंबक का उपयोग करके एक संक्षिप्त रूप से, ऐसा लगता है कि String.Substring() प्रत्येक सबस्ट्रिंग के लिए स्मृति आवंटित करता है। क्या मैं सही हूं कि यह मामला है? मैंने सोचा कि तार जरूरी नहीं है क्योंकि आवश्यक नहीं होगा।.NET मौजूदा स्ट्रिंग्स में इंगित करने के बजाय नए सबस्ट्रिंग क्यों बनाते हैं?

मेरा अंतर्निहित लक्ष्य IEnumerable<string> Split(this String, Char) एक्सटेंशन विधि बनाना था जो कोई अतिरिक्त मेमोरी आवंटित नहीं करता था।

+0

मैंने इसके बारे में बहुत कठिन नहीं सोचा है, या स्ट्रिंगबिल्डर के प्रतिबिंबक के साथ कार्यान्वयन को देखा है, लेकिन एक आईनेमेरेबल <स्ट्रिंगबिल्डर> स्प्लिट (यह स्ट्रिंगबिल्डर, चार) विधि काम करेगा? – Domenic

+0

यदि स्ट्रिंग।सबस्ट्रिंग() नई मेमोरी आवंटित नहीं करते हैं, स्ट्रिंग अचूक नहीं होगी –

उत्तर

22

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

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

+1

मैंने सोचा था कि मुख्य कारण तारों पर एल्गोरिदम के संबंध में था। यदि आप सुरक्षित रूप से यह मान सकते हैं कि एक स्ट्रिंग कभी नहीं बदलेगी तो आप इसके संदर्भों को सुरक्षित रूप से पास कर सकते हैं और यह भी मूल रूप से थ्रेडसेफ है। मुझे लगता है कि कचरा संग्रह के साथ भी संबंध है। – Spence

+1

@ स्पेन्स - यह अपरिवर्तनीयता का कारण है। स्ट्रिंग्स के बीच साझा बफर से बचने का कोई कारण नहीं है। एक बार जब आपके पास अपरिवर्तनीयता और जीसी हो, तो आप थ्रेड सुरक्षा या मौजूदा एल्गोरिदम को तोड़ने के बिना दृश्यों के पीछे साझा बफर को आसानी से कार्यान्वित कर सकते हैं। –

2

स्ट्रिंग कक्षाओं का उपयोग कर .net के अंदर घूमने के बिना संभव नहीं है। आपको एक सरणी के चारों ओर संदर्भों को पारित करना होगा जो उत्परिवर्तनीय था और सुनिश्चित करें कि कोई भी खराब नहीं हुआ है।

नेट जब भी आप इसे पूछते हैं तो एक नई स्ट्रिंग तैयार करेगा। इसके लिए केवल अपवाद स्ट्रिंग्स है जो कंपाइलर द्वारा बनाए जाते हैं (और आपके द्वारा किया जा सकता है) जिन्हें स्मृति में रखा जाता है और फिर स्मृति और प्रदर्शन कारणों के लिए स्ट्रिंग में पॉइंटर्स स्थापित किए जाते हैं।

0

क्योंकि तार .NET में अपरिवर्तनीय हैं, प्रत्येक स्ट्रिंग ऑपरेशन जिसके परिणामस्वरूप एक नई स्ट्रिंग ऑब्जेक्ट स्ट्रिंग सामग्री के लिए स्मृति का एक नया ब्लॉक आवंटित करेगा।

सिद्धांत रूप में, एक सबस्ट्रिंग निकालने पर स्मृति का पुन: उपयोग करना संभव हो सकता है, लेकिन इससे कचरा संग्रह बहुत जटिल हो जाएगा: क्या होगा यदि मूल स्ट्रिंग कचरा-संग्रहित हो? उस सबस्ट्रिंग का क्या होगा जो इसका एक टुकड़ा साझा करता है?

बेशक, .NET बीसीएल टीम को .NET के भविष्य के संस्करणों में इस व्यवहार को बदलने के लिए कुछ भी नहीं रोकता है। इसका मौजूदा कोड पर कोई असर नहीं पड़ेगा।

+6

जावा का स्ट्रिंग वास्तव में ऐसा करता है: सबस्ट्रिंग केवल मूल स्ट्रिंग में पॉइंटर्स हैं। हालांकि, इसका यह भी अर्थ है कि जब आप 200-एमआईबी स्ट्रिंग के 200-वर्ण वाले सबस्ट्रिंग लेते हैं, तो 200-एमआईबी स्ट्रिंग हमेशा स्मृति में चारों ओर झूठ बोलती है जब तक कि छोटे सबस्ट्रिंग कचरा-संग्रह नहीं होता है। – Joey

+0

मुझे लगता है कि यह मौजूदा कोड को प्रभावित कर सकता है क्योंकि यह इस व्यवहार के आसपास बनाया गया है। अगर लोग मानते हैं कि उनकी स्ट्रिंग को इंटर्न करने से इसे डुप्लिकेट करने से रोक दिया जाएगा और यह व्यवहार बंद कर दिया गया है तो यह काम करने वाले ऐप्स को स्मृति अपवादों से बाहर करने का कारण बन सकता है। – Spence

+0

आप इस व्यवहार के आसपास कैसे डिजाइन कर सकते हैं? तारों की अपरिवर्तनीयता के कारण, स्ट्रिंग क्लास के आंतरिक कार्यान्वयन में परिवर्तन होने पर कोड बनाने का कोई तरीका नहीं है जो टूट जाएगा। –

1

प्रत्येक स्ट्रिंग के पास स्ट्रिंग क्लास लागू होने के तरीके के साथ अपना स्वयं का स्ट्रिंग डेटा होना चाहिए।

public struct SubString { 

    private string _str; 
    private int _offset, _len; 

    public SubString(string str, int offset, int len) { 
     _str = str; 
     _offset = offset; 
     _len = len; 
    } 

    public int Length { get { return _len; } } 

    public char this[int index] { 
     get { 
     if (index < 0 || index > len) throw new IndexOutOfRangeException(); 
     return _str[_offset + index]; 
     } 
    } 

    public void WriteToStringBuilder(StringBuilder s) { 
     s.Write(_str, _offset, _len); 
    } 

    public override string ToString() { 
     return _str.Substring(_offset, _len); 
    } 

} 

आप तुलना की तरह अन्य तरीकों भी संभव है कि स्ट्रिंग निकालने के बिना ऐसा करने के लिए के साथ यह शरीर से बाहर कर सकते हैं:

आप अपनी खुद की सबस्ट्रिंग संरचना एक स्ट्रिंग के भाग का उपयोग करता है बना सकते हैं।

+0

किसी अन्य सबस्ट्रिंग में एक सबस्ट्रिंग के बारे में क्या? –

+0

हां, सबस्ट्रिंग संरचना के लिए यह एक और बनाना है जो स्वयं का हिस्सा है। – Guffa

0

स्ट्रिंग्स अपरिवर्तनीय हैं, इस बिंदु को जोड़ना, आपको यह होना चाहिए कि निम्न स्निपेट स्मृति में एकाधिक स्ट्रिंग उदाहरण उत्पन्न करेगा।

String s1 = "Hello", s2 = ", ", s3 = "World!"; 
String res = s1 + s2 + s3; 

S1 + s2 => नई स्ट्रिंग उदाहरण (temp1)

temp1 + S3 => नई स्ट्रिंग उदाहरण (temp2)

रेस temp2 लिए एक संदर्भ है।

+0

ऐसा लगता है कि संकलक लोग अनुकूलित कर सकते हैं। –

+0

यह कंपाइलर के साथ कोई समस्या नहीं है, यह भाषा को डिजाइन करने में एक विकल्प है। जावा के स्ट्रिंग्स के लिए समान नियम हैं। System.Text.StringBuilder उपयोग करने के लिए एक अच्छी कक्षा है जो "उत्परिवर्तनीय" तारों को अनुकरण करती है। –

+1

गलत - एस 1 + एस 2 + एस 3 स्ट्रिंग.कोनकैट को एक ही कॉल में बदल जाता है। यही कारण है कि 4 स्ट्रिंग तक स्ट्रिंग.फॉर्मैट या स्ट्रिंगबिल्डर (जो अपेक्षाकृत धीमी दोनों हैं) का उपयोग करना बेहतर नहीं है। यह देखने के लिए आईएल देखें कि कंपाइलर क्या करता है, और यह जानने के लिए कि आपके प्रोग्राम में क्या अच्छा प्रदर्शन करता है, एक प्रोफाइलर का उपयोग करें। अन्यथा आप यह भी कह सकते हैं "देखो, यह जूता है! उसने अपना जूता हटा दिया है और यह एक संकेत है कि जो लोग उसका अनुसरण करेंगे उन्हें भी ऐसा ही करना चाहिए!" कृपया पौराणिक लोगों के बजाय तथ्यात्मक उत्तर पोस्ट करें। –

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

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