2011-10-17 8 views
7

मैं this question hereबड़े स्ट्रिंग मुद्दों का कारण बनता है - लेकिन किसी भी मामले में यह एक स्ट्रिंग के रूप में अंत में

समस्या मेरे पास है

से अनुसरण कर रही हूं है मैं कुछ बड़े मुख्य रूप से एक MSMQ से आ रही वस्तुओं है कि है स्ट्रिंग्स। मैंने बड़े ऑब्जेक्ट हीप (LOH) में इन वस्तुओं को बनाने के लिए अपनी स्मृति समस्याओं को कम कर दिया है और इसलिए इसे खंडित किया है (पुष्टि की है कि प्रोफाइलर से कुछ मदद के साथ)।

मैंने ऊपर पोस्ट किए गए प्रश्न में मुख्य रूप से स्ट्रिंग को चार सरणी में विभाजित करने के रूप में कुछ कामकाज प्राप्त किए हैं।

मुझे जिस समस्या का सामना करना पड़ रहा है वह यह है कि स्ट्रिंग प्रसंस्करण (जो भी रूप में है) के अंत में मुझे उस स्ट्रिंग को किसी अन्य सिस्टम में भेजने की आवश्यकता है जिसका मेरा कोई नियंत्रण नहीं है।

  1. 85k से कम चार सरणियों की एक सरणी के रूप में यह का प्रतिनिधित्व करते हैं प्रत्येक (वस्तुओं की दहलीज LOH में रखा जाना करने के लिए)
  2. कम्प्रेस: ​​तो मैं निम्नलिखित समाधान के बारे में सोच रहा था इस स्ट्रिंग LOH में रखा है, यह प्रेषक अंत (यानी सिस्टम में इसे प्राप्त करने से पहले हम यहां रिसीवर है) के बारे में बात कर रहे हैं और तीसरे पक्ष के सिस्टम में इसे पार करने से पहले इसे डिकंप्रेस करते हैं।

जो कुछ भी मैं करता हूं - एक तरफ या दूसरा - स्ट्रिंग को पूरा करना होगा (कोई चार सरणी या संपीड़ित नहीं)।

क्या मैं यहां फंस गया हूं? मैं सोच रहा हूं कि एक प्रबंधित वातावरण का उपयोग करना यहां एक गलती थी और क्या हमें बुलेट काटने और सी ++ प्रकार के पर्यावरण के लिए जाना चाहिए।

धन्यवाद, Yannis

संपादित करें: मैं बिल्कुल को समस्या को संकुचित होता है कोड तैनात here

बड़े स्ट्रिंग है कि के माध्यम से LOH में रखा गया है आता है। मैंने बिंदु से प्रत्येक एकल प्रसंस्करण मॉड्यूल को हटा दिया है जहां मुझे संदेश प्राप्त हुआ है और स्मृति खपत की प्रवृत्ति वही है।

तो मुझे लगता है कि मुझे इस वर्ककॉन्टेक्स्ट को सिस्टम के बीच पारित करने के तरीके को बदलने की जरूरत है।

+0

क्या आप वास्तव में ऐसे संदेश भेज रहे हैं जो बड़े हैं? –

+2

आप स्ट्रिंग को अन्य सिस्टम में कैसे भेज रहे हैं? क्या आप धाराओं का उपयोग नहीं कर सकते? इसके अलावा, सी ++ का उपयोग करने से आपकी मदद नहीं हो सकती है, क्योंकि इसकी ढेर भी खंडित हो सकती है। – svick

+0

बस यह सुनिश्चित करने के लिए ... क्या आपने 'सर्वर' जीसी का उपयोग करने का प्रयास किया है? http://stackoverflow.com/questions/5423951/c-sharp-gc-for-server/5423979#5423979 – xanatos

उत्तर

0

आप शायद एक कक्षा को कार्यान्वित कर सकते हैं (इसे LargeString पर कॉल करें), जो पहले निर्दिष्ट तारों का पुन: उपयोग करता है और उनमें से एक छोटा संग्रह रखता है।

चूंकि स्ट्रिंग सामान्य रूप से अपरिवर्तनीय हैं, इसलिए आपको असुरक्षित पॉइंटर जॉगलिंग द्वारा हर बदलाव और नया असाइनमेंट करना होगा। रिसीवर को स्ट्रिंग पास करने के बाद, आपको इसे पुन: उपयोग के लिए मैन्युअल रूप से चिह्नित करने की आवश्यकता होगी। अलग-अलग संदेश की लंबाई भी एक समस्या हो सकती है, जब तक कि रिसीवर बहुत लंबे समय तक संदेशों का सामना नहीं कर सकता है, या आपके पास प्रत्येक लंबाई के तारों का संग्रह है।

शायद कोई अच्छा विचार नहीं है, लेकिन हो सकता है कि सी ++ में सबकुछ फिर से लिखना।

+0

धन्यवाद जेन्स - समस्या यह है: कार्यकर्ता नोड को कतार से काम मिलता है (उदाहरण यहां: http://pastebin.com/j0VTVrjK)। जब तक मैं लार्जस्ट्रिंग असाइन करता हूं (अच्छा विचार!) मैं पहले से ही वर्ककॉन्टेक्स्ट स्ट्रिंग आवंटित करता। या आप इसे एक char [] या कुछ में बदलने का सुझाव दे रहे हैं ताकि वह LOH पर न जाए और फिर बड़े स्ट्रिंग संरचना का पुन: उपयोग करें? – Yannis

+0

@Yannis: आपको निश्चित रूप से कहीं भी तारों पर अपने लंबे संदेश असाइन करने से बचने की आवश्यकता होगी। मुझे लगता है कि आपके दोनों सुझाए गए समाधान काम करेंगे। परिणाम को अन्य सिस्टम में पास करने के लिए आप बड़े स्ट्रिंग का उपयोग कर सकते हैं। – Jens

1

वैसे आपके विकल्प इस बात पर निर्भर करते हैं कि तृतीय पक्ष प्रणाली डेटा कैसे प्राप्त कर रही है। यदि आप इसे किसी भी तरह स्ट्रीम कर सकते हैं तो आपको इसे एक ही बार में स्मृति में रखना नहीं है। यदि ऐसा मामला है तो संपीड़न (जो संभवतया वास्तव में आपके नेटवर्क लोड में मदद करेगा यदि यह आसानी से संपीड़ित डेटा) बहुत अच्छा है क्योंकि आप स्ट्रीम के माध्यम से डिकंप्रेस कर सकते हैं और इसे तीसरे पक्ष के सिस्टम में भाग ले सकते हैं।

यदि आप लोहे थ्रेसहोल्ड के नीचे जाने के लिए अपने तारों को विभाजित करते हैं तो वही काम करेगा।

यदि नहीं तो मैं अभी भी एमएसएमक्यू संदेश पर पेलोड को विभाजित करने का समर्थन करता हूं, और फिर क्लाइंट को भेजने से पहले पुन: असेंबली के लिए प्रीलोएक्टेड और पुन: उपयोग बाइट एरे के मेमोरी पूल का उपयोग करता हूं। माइक्रोसॉफ्ट एक कार्यान्वयन आप http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.buffermanager.aspx

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

0

आप StringBuilder (4.0 संस्करण जो रस्सी की तरह कार्यान्वयन का उपयोग करते हैं) का उपयोग कर मानों को स्ट्रीम करने का प्रयास कर सकते हैं।

यह उदाहरण चाहिए Release मोड में और Start Without Debugging संलग्न (Ctrl-F5) के साथ क्रियान्वित किया जा। जीसी के साथ Debug मोड और Start Debugging गड़बड़ दोनों बहुत अधिक है।

public class SerializableWork 
{ 
    // This is very often between 100-120k bytes. This is actually a String - not just for the purposes of this example 
    public String WorkContext { get; set; } 

    // This is quite large as well but usually less than 85k bytes. This is actually a String - not just for the purposes of this example 
    public String ContextResult { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Initial memory: {0}", GC.GetTotalMemory(true)); 
     var sw = new SerializableWork { WorkContext = new string(' ', 1000000), ContextResult = new string(' ', 1000000) }; 
     Console.WriteLine("Memory with objects: {0}", GC.GetTotalMemory(true)); 

     using (var mq = new MessageQueue(@".\Private$\Test1")) 
     { 
      mq.Send(sw); 
     } 

     sw = null; 

     Console.WriteLine("Memory after collect: {0}", GC.GetTotalMemory(true)); 

     using (var mq = new MessageQueue(@".\Private$\Test1")) 
     { 
      StringBuilder sb1, sb2; 

      using (var msg = mq.Receive()) 
      { 
       Console.WriteLine("Memory after receive: {0}", GC.GetTotalMemory(true)); 

       using (var reader = XmlTextReader.Create(msg.BodyStream)) 
       { 
        reader.ReadToDescendant("WorkContext"); 
        reader.Read(); 

        sb1 = ReadContentAsStringBuilder(reader); 

        reader.ReadToFollowing("ContextResult"); 
        reader.Read(); 

        sb2 = ReadContentAsStringBuilder(reader); 

        Console.WriteLine("Memory after creating sb: {0}", GC.GetTotalMemory(true)); 
       } 
      } 

      Console.WriteLine("Memory after freeing mq: {0}", GC.GetTotalMemory(true)); 

      GC.KeepAlive(sb1); 
      GC.KeepAlive(sb2); 
     } 

     Console.WriteLine("Memory after final collect: {0}", GC.GetTotalMemory(true)); 
    } 

    private static StringBuilder ReadContentAsStringBuilder(XmlReader reader) 
    { 
     var sb = new StringBuilder(); 
     char[] buffer = new char[4096]; 

     int read; 

     while ((read = reader.ReadValueChunk(buffer, 0, buffer.Length)) != 0) 
     { 
      sb.Append(buffer, 0, read); 
     } 

     return sb; 
    } 
} 

मैं एक XmlReader में सीधे संदेश के Message.BodyStream पढ़ सकते हैं और फिर मैं तत्वों की आवश्यकता के लिए जा सकते हैं और मैं XmlReader.ReadValueChunk

का उपयोग कर अंत में कहीं नहीं मैं string वस्तुओं का उपयोग मात्रा में डेटा को पढ़ने। स्मृति का एकमात्र बड़ा ब्लॉक Message है।