C# StreamWriter ومشكلة إدارة الذاكرة StreamReader ، لماذا لا تستخدم الذاكرة لتكوين Dealocate؟

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

سؤال

لذلك أنا أستخدم قائد StreamReader الذي يستخدم MemoryStream للكتابة إلى StreamWriter وداخل هذا التطبيق ، لكن استخدام الذاكرة يزداد بمقدار 300 ميجابايت (من أحد المدخلات الأكبر) ولا يتم تخصيصه بعد الانتهاء من استخدامه:

StreamWriter log = new StreamWriter("tempFile.txt");
log.Write(reader.ReadToEnd());
log.Close();

reader.DiscardBufferedData();
reader.Close();
reader.Dispose();
memoryStream.Dispose();
log.Dispose();
GC.Collect();

قبل ذلك وبعد أن أحصل على استخدام ذاكرة الوصول العشوائي وقبل أن يكون 300 ميجابايت أقل من ما بعد ولكن لا أعرف السبب. لقد فعلت كل ما يمكنني التفكير فيه لإصدار تلك الذاكرة مع الأخذ في الاعتبار أن الشيء الوحيد الذي يجري هنا هو أن البيانات من القارئ يتم وضعها في الملف النصي لا أرى سبب حاجة إلى استخدام أي قدر كبير من الذاكرة مؤقتا. هل هناك شيء أفتقده؟ ... شكرًا.

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

المحلول

هل تنظر إلى ذاكرة الوصول العشوائي التي تستخدمها العملية نفسها؟ لا أتوقع أن ينخفض. ستتمسك هذه العملية بتلك الذاكرة وإعادة استخدامها لمزيد من المخصصات. لا يعيدها إلى نظام التشغيل. هذا هو الطريق. NET يميل إلى العمل.

أنت يستطيع من المحتمل أن تحصل عليها لإبعاد الذاكرة مع بعض مكالمة API CLR - لكن عادةً ما لا أفعل ذلك.

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

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

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

using (TextWriter writer = File.CreateText("tempFile.txt"))
{
    CopyText(reader, writer);
}

static void CopyText(TextReader reader, TextWriter writer)
{
    char[] buffer = new char[8192];
    int charsRead;
    while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
    {
        writer.Write(buffer, 0, charsRead);
    }
}

لاحظ أنه ما لم تقم بتغيير الترميز فعليًا ، يمكنك القيام بذلك دون استخدام ملف TextWriter/TextReader زوج للبدء مع.

بهذه الطريقة لن تحتاج إلى الحصول على السلسلة بأكملها في الذاكرة وكذلك تمثيله الثنائي (في ال MemoryStream). لا يزال لديك التمثيل الثنائي بالطبع - هل أنت لديك لكتابة كل شيء في MemoryStream لتبدأ؟

نصائح أخرى

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

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

على أي حال ، بعض الأشياء التي يمكنك القيام بها هي:

  • يمكنك محاولة تشغيل تطبيق مكثف للذاكرة آخر لمعرفة ما إذا كان وقت التشغيل يطلق الذاكرة عندما يحتاج النظام
  • يمكنك استخدام بعض .NET Profiler لمعرفة ما إذا كانت هناك أي كائنات حية تتوقع أن يتم جمعها بعد تشغيل الطريقة

لست متأكدًا مما إذا كان ذلك سيساعد ، لكن جرب البعض using النطاق:

using (StreamReader reader = new StreamReader(somestream))
using (StreamWriter log = new StreamWriter("tempFile.txt"))
{
    log.Write(reader.ReadToEnd());
}

في الجزء المذكور أعلاه ، كل من log, reader, ، و memoryStream لا تزال في نطاقها وبالتالي لا يمكن جمع القمامة. لا أعرف ما هو تنفس Dispose على هذه الكائنات ، ولكن من المحتمل تمامًا أنهم ما زالوا يحتفظون بالكثير من البيانات في الذاكرة حتى بعد ذلك Dispose يسمى (منذ ذلك الحين Dispose عادةً ما يغلق FileHandles ، والذاكرة غير المدارة ، وما شابه ، ولا يحذف بالضرورة المخازن المؤقتة الداخلية). إذا كنت تريد أن يعمل هذا كما هو متوقع ، فيجب عليك السماح لجميع الكائنات المشار إليها بالخروج من النطاق وتصبح غير مرجعية.

حقًا ، على الرغم من ذلك ، لا ينبغي أن تقلق بشأن هذا ما لم يكن استخدام الذاكرة يسبب لك ألمًا صريحًا.

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