سؤال

نميل في الغالب إلى اتباع أفضل الممارسات المذكورة أعلاه.

القي نظرة على سلسلة مقابل StringBuilder

لكن يمكن لـ StringBuilder رميها OutOfMemoryException حتى في حالة توفر ذاكرة كافية.إنه يطرح استثناء OOM لأنه يحتاج إلى "كتلة مستمرة من الذاكرة".

بعض الروابط للرجوع إليهاStringBuilder OutOfMemoryException

وهناك غيرها الكثير.....

كم منكم واجه هذه المشكلة أو علم بها وماذا فعلتم لحلها؟

هل هناك أي شيء مفقود؟

ملاحظة:لم أكن على علم بهذا.

لقد قمت بإعادة صياغة السؤال.

*** نفس الشيء يعمل مع التسلسل اليدوي (سوف أتحقق من ذلك وأقوم بتحديث SO).الشيء الآخر الذي أثار قلقي هو وجود ذاكرة كافية في النظام.لهذا السبب طرحت هذا السؤال هنا للتحقق مما إذا كان أي شخص قد واجه هذه المشكلة أو كان هناك خطأ كبير في الكود.

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

المحلول

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

إذا تسبب إنشاء سلسلة في حدوث OOM، فمن المحتمل أن تكون هناك مشكلة أكثر خطورة في تطبيقك.

تحرير ردا على التوضيح:

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

سيؤدي استخدام StringBuilder أيضًا إلى مضاعفة الذاكرة المطلوبة مؤقتًا نظرًا لأن السلسلة ستكون موجودة في نموذج System.String وStringBuilder في نفس الوقت لفترة قصيرة.

ولكن إذا تسببت إحدى الطرق في حدوث OOM والأخرى لا، فمن المحتمل أن يشير ذلك إلى مشكلة أكثر خطورة في برنامجك.

نصائح أخرى

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

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

ما مقدار الذاكرة التي نتحدث عنها؟أنا لا أتحدث عن الذاكرة الحرة أو الإجمالية في النظام، ولكن ما هو طول السلسلة التي تقوم بتسلسلها؟

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

عند هذه النقطة يجب عليك إعادة هيكلة الكود حقًا.

على سبيل المثال، إليك طرق مختلفة لمكافحة المشكلة:

  1. لا تحتفظ بقدر كبير من البيانات في الذاكرة في وقت واحد، ضعها على القرص أو شيء من هذا القبيل
  2. قم بتقسيمها، واحتفظ بقائمة من منشئي السلاسل/السلاسل وأضف إليها فقط ما يصل إلى طول معين قبل التبديل إلى قائمة جديدة، مما يبقي مشكلة "الذاكرة المستمرة" في وضع حرج
  3. قم بإعادة هيكلة الخوارزمية بحيث لا يتم تراكم غيغابايت من البيانات في الذاكرة على الإطلاق

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

إذا نظرت إلى كيف StringBuilder تم تنفيذه، سترى أنه يستخدم بالفعل ملف String للاحتفاظ بالبيانات (String لديه أساليب داخلية، من شأنها أن تسمح StringBuilder للتعديل في مكانه).

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

حسنًا، السؤال في الواقع هو، لماذا تحتاج إلى العمل مع سلاسل طويلة؟إذا تعثرت في هذه المشكلة، فمن المرجح أن تغير مفهومك.

هذه المشاكل تؤثر حتى على System.String فئة، لذلك يجب عليك بدلاً من ذلك تقسيم مدخلاتك إلى قائمة <سلسلة> ومعالجة البيانات بالتوازي، الأمر الذي من شأنه أن يزيد الأداء العام إذا تمت كتابته بشكل صحيح.

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

لقد كانت لدي تجربة مشابهة جدًا حيث كنت أقوم بإلحاق السلاسل ولكني نسيت إضافة String.Format.هكذا:

myStringBuilder.Append("1,""{0}""", someVeryLargeIntVariable)

كان ينبغي أن يكون:

myStringBuilder.Append(String.Format("1,""{0}""", someVeryLargeIntVariable))

لاحظ أن هذا هو رمز vb.net الخاص بي الذي فشل.لقد قمت بتكرار اختبار مماثل في C# مع:

myStringBuilder.Append('a', 1564544656);

ضد.

myStringBuilder.Append(string.Format("1,\"{0}\"", 1564544656));

لكن في حالتي، تسبب لي vb.net في مشكلة بسبب التحويلات الضمنية (لم أتمكن من موازنة التحويلات الضمنية) بالضبط نفس المشكلة في C #).

وآمل أن يساعد شخص ما.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top