كيف يبدو استهلاك ذاكرة الوصول العشوائي في StringBuilder؟

StackOverflow https://stackoverflow.com/questions/149551

  •  02-07-2019
  •  | 
  •  

سؤال

لدينا عدد قليل من العمليات التي نقوم فيها بعدد كبير من سلاسل السلاسل الكبيرة، وقد واجهنا مؤخرًا استثناء نفاد الذاكرة.لسوء الحظ، تصحيح التعليمات البرمجية ليس خيارًا، حيث يحدث هذا في موقع العميل.

لذا، قبل النظر في إصلاح الكود الخاص بنا، أود أن أسأل:ما هي خصائص استهلاك ذاكرة الوصول العشوائي لـ StringBuilder للسلاسل الكبيرة؟

خاصة أنها تقارن بنوع السلسلة القياسي.يزيد حجم السلاسل عن 10 ميغابايت، ويبدو أننا نواجه مشكلات يبلغ حجمها حوالي 20 ميغابايت.

ملحوظة:الأمر لا يتعلق بالسرعة بل بذاكرة الوصول العشوائي.

هل كانت مفيدة؟

المحلول

هنا دراسة لطيفة حول تسلسل السلسلة مقابل تخصيص الذاكرة.

إذا كان بإمكانك تجنب التسلسل، فافعل ذلك!

هذا أمر لا يفكر ، إذا لم يكن عليك التسلسل ولكن تريد أن تبدو رمز المصدر الخاص بك لطيفًا ، فاستخدم الطريقة الأولى.سيتم تحسينه كما لو كانت سلسلة واحدة.

لا تستخدم += التسلسل على الإطلاق. تحدث الكثير من التغييرات خلف مكان الحادث ، والتي ليست واضحة من الكود الخاص بي في المقام الأول.أنصح بالأحرى استخدام string.concat () بشكل صريح مع أي تحميل زائد (سلاسلان ، 3 سلاسل ، صفيف السلسلة).سيوضح هذا بوضوح ما يفعله الرمز الخاص بك دون أي مفاجآت ، مع السماح لنفسك بالتحقق من الكفاءة.

حاول تقدير الحجم المستهدف لـ StringBuilder.

كلما كان الأمر أكثر دقة في تقدير الحجم المطلوب ، كلما كان على الأوتار المؤقتة التي سيتعين على StringBuilder إنشاءها لزيادة المخزن المؤقت الداخلي.

لا تستخدم أية أساليب Format() عندما يكون الأداء مشكلة.

يشارك الكثير من النفقات العامة في تحليل التنسيق ، عندما يمكنك إنشاء مجموعة من القطع عندما يتم استبدال كل ما تستخدمه.يعد التنسيق () مفيدًا لقدرة القراءة ، ولكن أحد الأشياء التي يجب أن تذهب عندما تضغط على كل الأداء الممكنة من التطبيق الخاص بك.

نصائح أخرى

في كل مرة تنفد فيها مساحة StringBuilder، فإنه يعيد تخصيص مخزن مؤقت جديد يبلغ ضعف حجم المخزن المؤقت الأصلي، وينسخ الأحرف القديمة، ويسمح للمخزن المؤقت القديم بالحصول على GC'd.من المحتمل أنك تستخدم ما يكفي (أطلق عليه x) بحيث تكون 2x أكبر من الذاكرة المسموح لك بتخصيصها.قد ترغب في تحديد الحد الأقصى لطول سلاسلك، وتمريره إلى مُنشئ StringBuilder حتى تقوم بالتخصيص المسبق، ولا تكون تحت رحمة إعادة التخصيص المضاعفة.

قد تكون مهتمًا ببنية بيانات الحبال.هذا المقال: الحبال:النظرية والتطبيق يشرح مزاياها.ربما يكون هناك تطبيق لـ .NET.

تحديث ، للإجابة على التعليق] هل يستخدم ذاكرة أقل؟يبحث ذاكرة ستجد في المقالة بعض التلميحات.
في الأساس، نعم، على الرغم من الحمل الزائد للهيكل، لأنه يضيف الذاكرة عند الحاجة فقط.يجب على StringBuilder، عند استنفاد المخزن المؤقت القديم، تخصيص مخزن أكبر بكثير (والذي يمكن أن يؤدي بالفعل إلى إهدار الذاكرة الفارغة) وإسقاط المخزن القديم (الذي سيتم جمع القمامة فيه، ولكن لا يزال بإمكانه استخدام الكثير من الذاكرة في الوقت نفسه).

لم أجد تطبيقًا لـ .NET، ولكن يوجد على الأقل تطبيق C++ (في STL الخاص بـ SGI: http://www.sgi.com/tech/stl/Rope.html).ربما يمكنك الاستفادة من هذا التنفيذ.لاحظ أن الصفحة التي أشير إليها تحتوي على عمل حول أداء الذاكرة.

لاحظ أن الحبال ليست العلاج لجميع المشاكل:تعتمد فائدتها بشكل كبير على كيفية بناء أوتارك الكبيرة وكيفية استخدامها.تشير المقالات إلى المزايا والعيوب.

يعد Srigbuilder حلاً جيدًا تمامًا لمشاكل الذاكرة الناتجة عن تسلسل السلاسل.

للإجابة على سؤالك المحدد، لدى Stringbuilder حمل ثابت الحجم مقارنة بسلسلة عادية حيث يكون طول السلسلة مساويًا لطول المخزن المؤقت Stringbuilder المخصص حاليًا.من المحتمل أن يكون حجم المخزن المؤقت ضعف حجم السلسلة الناتجة، ولكن لن يتم إجراء المزيد من عمليات تخصيص الذاكرة عند التسلسل إلى Stringbuilder حتى يتم ملء المخزن المؤقت، لذلك فهو حقًا حل ممتاز.

بالمقارنة مع السلسلة، هذا رائع.

string output = "Test";
output += ", printed on " + datePrinted.ToString();
output += ", verified by " + verificationName;
output += ", number lines: " + numberLines.ToString();

يحتوي هذا الكود على أربع سلاسل يتم تخزينها كأحرف حرفية في الكود، اثنتان تم إنشاؤها في الطرق وواحدة من متغير، ولكنها تستخدم ستة سلاسل وسيطة منفصلة تصبح أطول فأطول.إذا استمر هذا النمط، فسيؤدي ذلك إلى زيادة استخدام الذاكرة بمعدل أسي حتى يبدأ GC في تنظيفه.

لا أعرف بالضبط نمط الذاكرة الخاص بمنشئ السلسلة ولكن السلسلة المشتركة ليست خيارًا.

عند استخدام السلسلة الشائعة، يؤدي كل تسلسل إلى إنشاء كائنين آخرين من السلسلة، ويرتفع استهلاك الذاكرة بشكل كبير، مما يؤدي إلى استدعاء أداة تجميع البيانات المهملة كثيرًا.

string a = "a";

//creates object with a

a += "b"

/creates object with b, creates object with ab, assings object with ab to "a" pointer
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top