هل تم إنشاء تسرب للذاكرة إذا لم يتم إغلاق MemoryStream في .NET؟

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

سؤال

لدي الكود التالي:

MemoryStream foo(){
    MemoryStream ms = new MemoryStream();
    // write stuff to ms
    return ms;
}

void bar(){
    MemoryStream ms2 = foo();
    // do stuff with ms2
    return;
}

هل هناك أي احتمال أن يفشل التخلص من MemoryStream الذي قمت بتخصيصه لاحقًا بطريقة ما؟

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

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

المحلول

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

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

نصائح أخرى

وأنت لن يتسرب أي شيء - على الأقل في التنفيذ الحالي

.

ودعوة تخلص لن تنظيف الذاكرة المستخدمة من قبل MemoryStream أي أسرع. أنه سوف وقف تيار الخاصة بك من كونها قابلة للتطبيق للمكالمات القراءة / الكتابة بعد المكالمة، التي قد تكون أو لا تكون مفيدة لك.

إذا كنت متأكدا تماما من أن ل<م> لا تريد الانتقال من MemoryStream إلى نوع آخر من تيار، وانها لن تفعل أي ضرر لعدم استدعاء تخلص. ومع ذلك، انها ممارسة جيدة عموما ويرجع ذلك جزئيا إذا كنت من أي وقت مضى <م> قيام تغير لاستخدام تيار مختلف، كنت لا ترغب في الحصول على لعض من الصعب العثور على لعلة لأنك اخترت الطريق السهل في وقت مبكر على. (من ناحية أخرى، هناك حجة YAGNI ...)

والسبب الآخر أن نفعل ذلك على أي حال هو أن تطبيق جديد <م> قد إدخال الموارد التي سيفرج عنهم على التخلص.

على نعم هناك <م> من تسرب ، أو اعتمادا على كيفية تعريف التسرب وكم لاحقا تقصد ...

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

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

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

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

وهذا هو أجبت، ولكن سأضيف فقط أن مبدأ الطراز القديم جيدة من مخبئه المعلومات يعني أنك قد ترغب في نقطة ما في المستقبل إلى ريفاكتور:

MemoryStream foo()
{    
    MemoryStream ms = new MemoryStream();    
    // write stuff to ms    
    return ms;
}

إلى:

Stream foo()
{    
   ...
}

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

ويمكنك بعد ذلك سوف تحتاج أن تكون في ورطة إذا كنت لم تستخدم تخلص في تنفيذ شريط:

void bar()
{    
    using (Stream s = foo())
    {
        // do stuff with s
        return;
    }
}

وجميع تيارات تنفيذ IDisposable. التفاف تيار الذاكرة الخاصة بك في العبارة باستخدام وسوف يكون على ما يرام ومدهش. يتم إغلاق كتلة باستخدام سيضمن تيار والتخلص مهما كانت.

وأينما كنت استدعاء فو يمكنك القيام به باستخدام (مللي MemoryStream = فو ()) وأعتقد أن عليك أن تكون لا تزال على ما يرام.

الاتصال .Dispose() (أو التفاف مع Using) غير مطلوب.

سبب اتصالك .Dispose() هو الافراج عن المورد في أقرب وقت ممكن.

فكر في خادم Stack Overflow، على سبيل المثال، حيث لدينا مجموعة محدودة من الذاكرة وآلاف الطلبات الواردة.لا نريد الانتظار لجمع البيانات المهملة المجدولة، بل نريد تحرير تلك الذاكرة في أسرع وقت ممكن حتى تكون متاحة للطلبات الواردة الجديدة.

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

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

أوصي بتغليف MemoryStream bar() في using البيان بشكل رئيسي من أجل الاتساق:

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

شيء آخر أفعله عادة في حالات مثل foo() عند إنشاء وإرجاع IDisposable هو التأكد من أن أي فشل بين إنشاء الكائن و return تم اكتشاف الاستثناء، والتخلص من الكائن، وإعادة الاستثناء:

MemoryStream x = new MemoryStream();
try
{
    // ... other code goes here ...
    return x;
}
catch
{
    // "other code" failed, dispose the stream before throwing out the Exception
    x.Dispose();
    throw;
}

إذا كائن تنفذ IDisposable، يجب استدعاء الأسلوب .Dispose عند الانتهاء من ذلك.

في بعض الأشياء، وتخلص يعني نفس انهيار والعكس بالعكس، في هذه الحالة، إما أمر جيد.

والآن، بالنسبة لسؤالك معين، لا، أنت لن تسرب الذاكرة.

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

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

وMemorySteram ليست سوى مجموعة من البايت، الذي يدار الكائن. ننسى أن التخلص أو إغلاق هذا أي تأثير الجانب الآخر من فوق رأسه من وضع اللمسات الأخيرة.
انظروا فقط constuctor أو طريقة تدفق من MemoryStream في العاكس، وسوف يكون واضحا لماذا لا داعي للقلق بشأن إغلاق أو التخلص أنه بخلاف مجرد مسألة التالية الممارسات الجيدة.

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