سؤال

ما هي الموارد التي يجب تنظيفها يدويًا؟ ج# وما هي عواقب عدم القيام بذلك؟

على سبيل المثال، لنفترض أن لدي الكود التالي:

myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black);
// Use Brush

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

ما هي الموارد الأخرى التي أحتاجها للتنظيف يدويًا؟

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

المحلول

من الناحية الفنية، يجب التخلص من أي شيء يرث من IDisposable بشكل استباقي.يمكنك استخدام عبارة "استخدام" لتسهيل الأمور.

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

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

الشيء الجميل في IDisposable هو أنه يمنحك القدرة على ذلك بشكل استباقي تحرير المورد الأساسي غير المُدار.في بعض الأحيان تريد حقًا القيام بذلك - فكر في اتصالات الشبكة وموارد الملفات على سبيل المثال.

نصائح أخرى

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

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

using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
    // use myBrush
}
  • يتعامل مع هياكل بيانات النوافذ الداخلية.
  • اتصالات قاعدة البيانات.
  • مقابض الملفات.
  • اتصالات الشبكة.
  • مراجع COM/OLE.

والقائمة تطول.

من المهم الاتصال Dispose أو الأفضل من ذلك، استخدم using نمط.

using (SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Black))
{
    // use myBrush
}

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

في حالة System.Drawing.Brush, ، سيحتفظ Windows بهياكل النوافذ الداخلية للفرشاة المحملة في الذاكرة حتى تحرر جميع البرامج مقبضها.

يمكن أن تختلف عواقب عدم التخلص من معرفاتك الشخصية من أداء لا يُذكر إلى تعطل تطبيقك.

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

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

إما استخدام

using (new DisposableThing...
{
    ...
}

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

class MyClass : IDisposable
{
    private IDisposable disposableThing;

    public void DoStuffThatRequiresHavingAReferenceToDisposableThing() { ... }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    //etc... (see IDisposable on msdn)

}

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

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

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

الخدعة التي أستخدمها عندما لا أستطيع تذكر ما إذا كان كائن معين هو مورد يمكن التخلص منه هي كتابة ".Dispose" (على الأكثر!) بعد الإعلان لجعل Intellisense يتحقق مني:

MemoryStream ms = new MemoryStream().Dispose

ثم احذف .Dispose واستخدم التوجيه use():

using(MemoryStream ms = new MemoryStream())
{
  ...
}

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

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

إذا تمت إدارتها (أي.جزء من الإطار) لا داعي للقلق بشأن ذلك.إذا قام بتطبيق IDisposable، فما عليك سوى لفه في ملف using حاجز.

إذا كنت تريد استخدام الموارد غير المُدارة، فأنت بحاجة إلى قراءة أدوات الإنهاء النهائية وتنفيذ IDisposable بنفسك.

هناك الكثير من التفاصيل تحت هذا السؤال

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

أثناء استخدام التخلص أو التدمير in.net، يجب على المرء أن يفهم أن الوقت الذي يتم فيه استدعاء وظيفة التخلص بواسطة GC ليس حتميًا.ولهذا السبب يوصى باستخدام استخدام أو استدعاء التخلص بشكل صريح.

عند استخدام موارد مثل الملفات، يجب تحرير كائنات الذاكرة مثل الإشارات والموارد الموجودة خارج عالم .net المُدار.

على سبيل المثال، تحتاج إلى التخلص من SolidBrush لأنه كائن GDI ويعيش خارج عالم .net.

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

إحدى المزايا الكبيرة لـ C# مقارنةً بـ C/C++ هي أنك لا تحتاج إلى الاهتمام بتحرير الكائنات المخصصة (في معظم الأوقات على الأقل)؛يقوم gc بذلك عندما يقرر وقت التشغيل (استراتيجيات مختلفة متى/كيفية القيام بذلك).

لا يتم الاهتمام بالعديد من الموارد بواسطة gc:الملف، والموارد المرتبطة بمؤشر الترابط (الأقفال)، واتصالات الشبكة، وما إلى ذلك...

مكان واحد يجب توخي الحذر فيه هو الأشياء التي ينظر صغيرة بالنسبة لـ GC ولكنها ليست ...في SharePoint API على سبيل المثال، يكون لكائن SPWeb مساحة صغيرة فيما يتعلق بـ GC وبالتالي ستكون له أولوية منخفضة للتجميع، ولكنه استحوذ بالفعل على مجموعة من الذاكرة (في الكومة على ما أعتقد) التي لا يفعلها GC لا أعرف عن.سوف تواجه بعض مشكلات الذاكرة الممتعة إذا كنت تبحث عن مجموعة كاملة من هذه المشكلات، على سبيل المثال، تذكر دائمًا استخدام الاستخدام أو التخلص منه!

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

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

هناك بعض الأشياء التي تحتاج إلى التنظيف يدويًا، ولكن هذه مؤشرات تم استردادها من مصادر غير مُدارة، مثل استدعاءات DLL، ومع ذلك، لا يوجد شيء داخل .NET Framework يحتاج إلى هذه المعالجة.

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