الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

Garbage collector in .Net

بدأه eng_3llam في 22 مارس 2006 · 5 رد · 4,102 مشاهدة · في Microsoft Visual C#.NET
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

بسم الله الرحمن الرحيم

السلام عليكم

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

كيفية إنشاء كائن داخل الManaged heap

ما هو الApplication root وماهى أهميتة للكائن؟

العلاقة بين الgenerations and objects

Finalization and IDisposable interface

بعض الداول الموجودة داخل الGarbage collector class

عملية ال Resurrection (الإحياء)

Weak reference and strong reference

الجزء الاول

مقـــــــــدمة بسيطة:-

كلنا عارفين أزاى أنشى values and objects وعارفين أن الreference types تخزن داخل الManaged heap ( Managed heap is just a random chuck of memory that accessed by CLR ) زى الclasses وأيضا عارفين أن الvalue types بتخزن حسب المكان المعرفة فية بمعنى لو كانت معرف داخل class يبقى هتتخزن ف الManaged heap وأيضا لو كانت معرفة داخل structure يبقى هتخزن داخل الstack . حيث ان عملية الreclaim للذاكرة لو كانت مقتصرة على المبرمج سوف تكون صعبة جدا وممكن تبعدة عن المشلكة الاساسية التى يحاول حلها وبالتالى الGarbage collector سهل العملية على المبرمج من تتبع أستعمال الذاكرة ومتى يحرر الMemory ولكن فى بعض الأوقات كال unmanaged resources (كما سنعرف ) الGC لا يعرف كيفية تحرير الMemory وبالتالى فهذ يجبر المبرمج على كتابة كود بسيط يعرف من خلالة الGC أزاى يتعامل مع الunmanaged resources حيث فى الدوت نت يتم كتابة الDispose , Finalize or Close methods (كما سنرى) طب دلوقتى عاوزين نعرف أزاى يتم عمل Clean للunreachable resources الموجودة فى الmanaged heap وأزاى أقدر أتحكم فى الGC .

How objects store in Managed Heap?

تعالى نعرف أزاى يتم عمل Initialize and allocate to object

على أفتراض أن عندنا Employee class كما موضح بالكود

class Employee
    {
        private string m_name;
        private int m_age;
        public Employee(string name , int age)
        {
            this.m_name = name;
            this.m_age = age;
        }

        public void PrintData()
        {
            Console.WriteLine("the name is {0} and age is {1}",this.m_name,this.m_age);

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Employee emp = new Employee("Mohammed Allam", 19);
            emp.PrintData();
        }
    }

فى ذلك السطر

          Employee emp = new Employee("Mohammed Allam", 19);

تم أستخدام الnew keyword حيث بترجع reference للobject(emp) الموجود داخل الManaged heap وليس الكائن ذات نفسة كما موضح ف تلك الصورة

23_03_06_11_56_38_11431437981.jpg

طب فى حالة عمل running للبرنامج وعند فتح الAssembly بأستخدام الildasm.exe سنجد الnew keyword متمثلة فى الnewobj instruction كما موضح فى تلك الصورة

23_03_06_11_58_09_1143143889_.JPG

تعالى نعرف المهام اللى بيقوم بيها الinstruction newobj

1-يتم حساب المساحة الكلية المراد حجزها لذلك المتغير وذلك عن طريق data types للمتغيرات الموجودة داخل ذلك الclass وأيضا الdata typesللbase class

2-وبعد ذلك يتم فحص الManaged heap هل عندك مساحة كافية لتخزين ذلك الobject لو فية مساحة فى تلك الحالة يتم مناداة الcustom constructor وبعد ذلك يتم إرجاع reference لذلك الobject حيث المساحة أو المكان اللى تم تخزين فية ذلك الobject كان مشار الية بمؤشر يسمى Next object pointer (NextObjPtr حيث عبارة عن المكان اللى سيتم تخزين فية الNext object داخل الManaged heap ) كما موضح فى تلك الصورة

23_03_06_11_58_58_11431439383.JPG

حيث فى تلك الصورة عندنا object a,b,c موجودين داخل الmanaged heap والNextObjPtr يشير الى المكان المتاح لاى object جديد سيتم تخزينة

حيث عند أنشاء object يتم تحديد المساحة كما عرفنا سابقا ويتم إضافة تلك المساحة المحددة الى الNextObjPtr

أذا كان ال NextObjPtr وصل الى نهاية المساحة المحددة للManaged heap وبالتالى يبدأ الGC لعمل clean كما سنعرف حتى يتيح تخزين ذلك الobject

Theory of Application Root

أى APP. لة مجموعة من ال roots حيث الroot عبارة عن مساحة مخزنة تشير الى الobject الموجود داخل ال heap

حيث الroot ممكن أن يكون من أحدى الحالات الأتية

1-Global or static object

EX: public static Employee emp;

2-Object parameter passed to method

Public void PrintData(Employee emp)
{
//…..
}

3-ٍStatic Filed

EX: public static int count = 9;

4- Local object declared in method

Public void Add()
{
Employee emp = new Employee("A",1);
}

حيث تلك الroots تحدد عن طريق الـJIT(Just In Time compiler) وأيضا الCLR

عند بداية تشغيل الGC (Garbage collector ) يعتبر جميع الobjects المخزنة داخل الheap عبارة عن Garbage بمعنى أن No Application roots refer to any object in heap وبكدة يبدأ عمل الGC وبيدأ يختبر هل كل object موجود متصل بالroot بتاعة ولا لأ وعلى هذا الاساس يتم بناء الobject graph بواسطة الCLR وأيضا بيكون حريص فى الcircular objects حيث عمرها ماهتكون infinite

على إفتراض ان عندنا objects كما موجود فى تلك الصورة

23_03_06_12_00_12_11431440124.JPG

حيث جميع الobjects الموجودة جزء من الobject graph وعند أضافة الobject D حيث لاحظ المجمع (Collector ) أنة معتمد على الobject h والobjh موجود ف الgraph

وهكذا الGC يبدأ يختبر كل obj هل لة root ؟لو لة يضيفة فى الgraph طب لو لو ملهوش وبالتالى يكون unreachable object وبالتالى يبدأ الGC أيضا فى إختبار هل يوجد unreachable objects عبارة عن finalizable (كما سنعرف) وبالتالى يتم وضع مؤشر لة داخل الfreachable queue ليتم مناداة الfinalize لتحرير الذاكرة من ذلك الكائن

وبعد ذلك يتم عمل deallocate للunreachable objects اللى مش محتاجة الfinalization process وذلك عن طريق

تحريك الreachable object لاسفل فى الheap وبعد ذلك يبدأ فى عمل Defragment للheap وبالتالى بسبب التحريك الreachable objects يتم عمل update للApplication roots التى تشير الى objects فى المكان الجديد وأيضا الNextObjPtr يير الى المساحة الفارغة

حيث فى تلك اللحظة تم إقاف باقى الthreads حتى يتم عملية الclean وبعد ذلك تبدأ باقى الthreads فى عملها وأيضا يتم إنشاء thread أخرى منفصلة للunreachable objects اللى محتاج عمل finalize لها قبل حذفها من الذاكرة

كما موصح فى تلك الصورة

23_03_06_12_01_04_11431440645.JPG

حيثتم حذف الB,E,G,I,J

حيث الGC لا يبدأ عملة ألا فى حالة أن الHeap is full

Understanding Object Generation

Object Generation عبارة عن ميكانيزم يستخدم بواسطة الGC لتحسين الاداء حيث عند عمل Collect to unreachable object مش معقول أنة هيبدأ يفحص كل الobjects الموجودة داخل الheap حيث لو كان كدة هياخد وقت طويل وبالأخص فى البرامج الكبيرة وعلشان نحسن الأداء أى object موجود داخل الheap لازم يندرج تحت أى جيل من الاجيال التالية

Generation 0 أى كائن جديد لسة معمول لة create يندرج تحت ذلك الجيل حيث أنة لم يتم فحصة من قبل الGC

Identifies newly allocated object that has never been marked for collection.

كما موضح فى تلك الصورة حيث تم أنشاء مجموعة objects لم يتم فحصها بالGC

23_03_06_12_02_15_11431441356.JPG

دلوقتى لو حبيت أضيف كائنات أخرى وكان الheap مليان وبالتالى يبدأ الGC حيث يبدأ بتحليل للheap وبالذات الgeneration 0 ويتم عمل clean للunreachable objects وباقى الكائنات اللى نجت من عملية ال)clean بسبب وجود App root لها )تندرج تحت الGeneration 1

لو حبينا نوصف الGeneration 1 هيبقى عبارة عن الobjects اللى نجت من عملية التنظيف للgeneration 0 يعنى تم عمل تحقيق معها مرة واحدة بواسطة الGC

كما موضح فى تلك الصورة

23_03_06_12_02_49_11431441697.JPG

حيث الobjects a , b, d,g,j تم نقلهم الى الgeneration 1 وتم إضافة الكائنات الجديدة k,l,m,n

طب لو ضيفت مرة أخرى more objects والمساحة الموجودة فى الgeneration 0 غير كافية وبالتالى سيتم أيضا عمل clean لل generation 1 والكائنات التى نجت من عملية التنظيف للجيل الاول يتم إدراجها تحت الgeneration 2

حيث الgeneration 2 يعتبر Highest generation المدعم بواسطة الruntime garbage collector أما لو المساحة غير كافية يتم عمل clean للجيل التانى والكائنات الناجية من تلك العملية تظل فى ذلك الجيل

كما موضح فى تلك الصورة عند أضافة الo,p objects سيتم عمل clean أولا الى الgeneration 0 حيث المساحة لم تكفى يتم عمل clean للgeneration 1 وأيضا المساحة لم تكفى يتم عمل clean للgeneration2

كما موضح فى تلك الصورة

23_03_06_12_03_37_11431442178.JPG

The System.GC Types

دلوقتى تعالى نشوف الGC class وبعض الدوال الموجودة فية والتى تمكنا بالتحكم فى الGC والتعامل معة حيث يفضل أستخدام تلك الدوال فى حالة الunmanaged resources

MaxGeneration property  حيث ترجع أكبر قيمة للاجيال الموجودة هى 2 حيث عندنا ثلاث أجيال 0و1و2 

Void GC.Collect(int32 Generation )     حيث تحدد أى جيل عاوز أعمل collect للunreachable objects الموجودة داخلة حيث تستقبل رقم صحيح يبدأ من 0 الى الGC.MaxGeneration حيث عند عمل pass للجيل رقم 0 سيتم عمل collect لة أما عند عمل pass للجيل الاول وبالتالى يتم عمل collect للجيل رقم 0و1 وأيضا عند عمل pass للجيل الثانى فى تلك الحالة سيتم عمل collect to unreachable objects الموجودة داخل كل من الاجيال 0و1و2بالترتيب.

Void GC.Collect() فى تلك الحالة  تكون متساوية ل GC.Collect(GC.MaxGeneration) وبالتالى سيتم عمل تجميع لجميع الكائنات التى لم يعد لها root فى جميع الاجيال0و1و2 على الترتيب  ايضا;-) 

حيث يفضل ترك عملية الcollect للGC فى حالة الManaged resources أما فى حالة الunmanaged يفضل تعريف الGC كيفية تخليص الmemory  من الunmanaged resources 


Int32 GetGeneration(object obj)  
Int32 GetGeneration(WeakReference wr) حيث الدالة الاولى يتم أعطائها كائن معين والثانية تأخذ كائن من النوعWeakReference (سنتعرف علية كمان شوية بأذن الله) وكلاهما يرجعان رقم الجيل الموجود بة ذلك الobject

 GetTotalMemory(Boolean ForceFullCollection) 
      ترجع المساحة المحجوزة للManaged heap  وتكون بالبايت  وذلك المتغير الboolean  لمعرفة هل انتا عاوز تعرف المساحة المستخدمة حاليا ف الmanaged heap بعد ما أعمل collect ولا قبل 
إذا كان true يبقى أعمل الاول collect وبعد كدة رجعلى المساحة المستخدمة وfalse رجع المساحة بدون ماتعمل collect 

WaitForPendingFinalizers() معناها أعمل وقوف مؤقت لجميع الthreads النشيطة لحد ما أعمل finalize للobjects 
حيث تلك الدالة يجب أن تنادى بعد ال()GC.Collect

تعالى نشوف مثال بسيط على تلك الدوال كما موضح

static void Main(string[] args)
        {
            Employee emp = new Employee("Mohammed Allam", 19);
            //emp.PrintData();
            Console.WriteLine();


            //Get number of generatios
            Console.WriteLine("Number of generation is {0}",GC.MaxGeneration+1);
            //Print number of bytes on heap
            Console.WriteLine("Total memory before collecting operation is {0}  bytes",GC.GetTotalMemory(false));
            //get generation of emp object.
            Console.WriteLine("Emp obj in Generation {0}\n",GC.GetGeneration(emp));

            GC.Collect(0);
            GC.WaitForPendingFinalizers();

            Console.WriteLine("After collect generation 0 :");
            Console.WriteLine("Now Emp obj hold in generation {0}\n",GC.GetGeneration(emp));

            //Collect to generation 0 and 1
            GC.Collect(1);
            GC.WaitForPendingFinalizers(); //Temporarily halt for other threads

            Console.WriteLine("After collecting generation 0 and 1 :");
            Console.WriteLine("Now Emp obj hold in generation {0}\n", GC.GetGeneration(emp));

            //Print how many times a generation has been swept.
            Console.WriteLine("Gen 0 has been swept {0} times",GC.CollectionCount(0));
            Console.WriteLine("Gen 1 has been swept {0} times", GC.CollectionCount(1));
            Console.WriteLine("Gen 2 has been swept {0} times", GC.CollectionCount(2));



        }

والoutput كما موضح فى تلك الصورة

23_03_06_12_04_38_11431442789.JPG

تم تعديل هذه المشاركة بواسطة eng_3llam في 23 مارس 2006 في 23:05

Muhammad Allam

Computer Science

@Resource(MappedURL="My Blog" )

#2

الجزء الثانى

Finalization process

زى ماعرفنا سابقا أن لوعندى فى البرنامج unmanaged resources يبقى لازم أقول للCLR إزاى يعمل clean لتلك المصادر وذلك أول technique تعريف الfinalize method حيث تلك الدالة موجودة فى الMaster class (object) كما موضح

    public class object
{
    protected virtual void Finalize()
{}
}

حيث تلك الدالة يتم مناداتها أوتوماتيك فى حالة إنتهاء الApplication domain (APPDomain يستخدم لإستضافة الexecutable Assembly or external libraries ) وبالتالى بديهى كدة لو حبيت أنشاء كلاس بة مصادر غير مدارة يبقى أنا لازم أعمل override لتلك الدالة كما موضح فى ذلك الكود

class UnManagedResources
    {
   //Error 
        protected override void Finalize()
        {
            //write unmanaged resurces such using COM interoperability tasks.
        }

}

حيث عند عمل compile للبرنامج ستجد خطأ كما موضح

"Don't override object.Finalize instead provide a destructor"

معنى كدة من الخطأ الموضح أن لو حيبت أعرف الfinalize يبقى أعرفها بس بطريقة غير مباشرة عن طريق أستخدام الdestructor لية؟؟

لان الكود المكتوب داخل الdestructor يتم وضعة داخل الfinalize فى الCIL كما سنرى

وبالتالى سيتم تعديل الكود كما يلى

  class UnManagedResources
    {       
        //write unmanaged resurces such using COM interoperability tasks.
        //.......
        ~UnManagedResources ()
        {
            //Clean up unmanaged resources here.

            //Beep when destroyed(kust for testing)
            Console.Beep();
        }
        //.......
 }

وعند عمل run للبرنامج وفتح الEXE بواسطة الildasm.exe ستجد الdestructor عبارة عن دالة الfinalize والكود اللى مكتوب داخل الdestructor مكتوب بين try-finally كما موضح

23_03_06_12_08_51_11431445311_.JPG

Detailing the Finalization process

عند حجز مساحة للobject فى الheap حيث الruntime أوتوماتيك يشوف هثل ذلك الobject يدعم الfinalize() لو كان كذلك يعرف الكائن بfinalizable object وبالتالى يتم حجز مؤشر لذلك الكائن داخل طابور يسمى Finalization queue

حيث الFinalization queue عبارة عن طابور يتم التحكم فية عن طريق الGC حيث كل كائن داخل ذلك الطابور يوجد لة الfinalize method الخاصة بة التى سيتم مناداتها قبل عمل تصليح للذاكرة من ذلك الكائن

حيث كما موضح فى تلك الصورة عندنا مجموعة من الكائنات الموجودة داخل الheap بعضها متصل بالroot الخاص بة والبعض الاخر unreachable عند إنشاء مجموعة من الكائنات مثلC,E,F,I,J حيث كل كائن من تلك الكائنات معرف لة الfinalize method وبالتالى هيجيى الruntime ويعرف أن كل كائن من الكائنات معرف لة الfinalize method وبالتالى سيتم إضافة مؤشر لكل كائن داخل الfinalization queue كما موضح فى تلك الصورة

23_03_06_12_10_28_114314462811.JPG

على إفتراض ان تلك الكائنات لم يعد لها أى إستخدام وهم B,E,G,H,I,J وبالتالى سيبدأ الGC فى عملة المعتاد

أول حاجة هيعملها أنة هيعمل scan على الfinalization queue هل فى مؤشر لأى كائن من الunreachable objects ولالأ لو فية زى فى حالتنا زى الobject E,J,I وبالتالى سيتم حذف ذلك المؤشر من الfinalization queue ووضعة فى freachable queue (حيث عبارة عن طابور يتم التحكم فية عن طريق الGC ويحتوى على مؤشر للكائنات التى على أستعداد ليتم مناداة الfinalize method

حيث فى تلك الصورة ستجد أن الكائنات التالية B,G,H تم عمل reclaimed لهم وذلك لان تلك الكائنات لا تملك الfinalize method أما الكائنات E,I,J لم يتم عمل reclaim لهم لانهم منتظرين مناداة الfinalize الخاصة بكل كائن منهم

كما موضح فى تلك الصورة

23_03_06_12_11_24_11431446841_.JPG

حيث توجد thread خاصة بالقيام بعملية الreclaim للكائنات الموجودة داخل الfreachable queue حيث تلك الthread تنشط عندما يتم وضع أى كائن داخل ذلك الqueue وبالتالى يتم حذف مؤشر كل كائن من ذلك الطابور ومناداة الدالة الخاصة بة ليتم عمل reclaim للذاكرة.

Freachable queue حيث الf تدل على ان ذلك الكائن منتظر لfinalization operation وأن كل كائن لة finalize method أما الreachable تدل على أن ذلك الكائن مازال reachable حيث يتم إعتبار المؤشر الموجود داخل الfreachable queue بالroot .بعد عمل reclaim للكائنات الاخرى سيتم عمل reclaim للكائنات الموجودة داخل الfreachable queue

كما موضح فى تلك الصورة

23_03_06_12_12_17_114314473713.JPG

IDisposable interface

يوجد البديل لإستخدام الfinalize method وهو تعريف الDispose method الموجودة داخل الIDisposable interface

public interface IDisposable
    {
        public void Dispose();
    }

وبالتالى عند عمل Implements لذلك الinterface يبقى أقدر أستخدم تلك الدالة حيث يتم إستدعائها Manually كما فى ذلك الكود

class UnManagedResources:IDisposable
    {       
        //write unmanaged resurces such using COM interoperability tasks.
        //.......
       public void Dispose()
        {
            //Clean up unmanaged resources here.

           
        }
        //.......
        
    }

    
    class Program
    {
        static void Main(string[] args)
        {
            UnManagedResources obj = new UnManagedResources();
            if (obj is IDisposable) //Check if obj support Dispose method
            {
                obj.Dispose();
            }
        }

حيث الفرق بينهما أن الfinalize مقتصرة فقط على الclasses أما الDispose ممكن يتم عمل implement لها عن طريق class or struct

حيث فى أغلب أستخدام الdispose يتم أستدعائها داخل الfinally block كما موضح

UnManagedResources obj = new UnManagedResources();
            try
            {
                //use obje members here
            }

            finally
            {
                //Always call dispose 
                obj.Dispose();
            }

حيث ممكن الاستغناء عن ذلك عن طريق أستخدام الusing keyword كما يلى

//Dispose method called automatic when exit from using scope.
            using (UnManagedResources obj = new UnManagedResources())
            {
                //use obj members here     
            }

حيث عند إستخدام الusing keyword وفتح الEXE عن طريق ildasm.exe سنجد الusing عبارة عن try-finally وإستدعاء الdispose داخل الfinally block

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
// Code size       29 (0x1d)
  .maxstack  2
  .locals init ([0] class ConsoleApplication5.UnManagedResources obj,
           [1] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication5.UnManagedResources::.ctor()
  IL_0006:  stloc.0
  .try
  {
    IL_0007:  nop
    IL_0008:  nop
    IL_0009:  leave.s    IL_001b
  }  // end .try
  finally
  {
    IL_000b:  ldloc.0
    IL_000c:  ldnull
    IL_000d:  ceq
    IL_000f:  stloc.1
    IL_0010:  ldloc.1
    IL_0011:  brtrue.s   IL_001a
    IL_0013:  ldloc.0
    IL_0014:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0019:  nop
    IL_001a:  endfinally
  }  // end handler
  IL_001b:  nop
  IL_001c:  ret
} // end of method Program::Main

Use Finalize and Dispose methods

إحنا عرفنا أن الFinalize يتم إستدعائها أوتوماتيك قبل حذف الكائن أما الDispose يتم إستدعائها يدويا او أوتوماتيك عن طريق أستخدام using keyword للتأكد من أن الdispose تم مناداتها كما عرفنا

حيث فى بعض البرامج يتم تعريف الدالتين علشان لو نسيت ولم أستخدم الdispose أو الusing keyword يبقى الfinalize هيتم إستدعائها أوتوماتيك أما لو أستخدمت الdispose يبقى فى تلك الحالة لازم أعرف الGC أن مايستدعيش الfinalize مرة أخرى وذلك عن طريق GC.SuppressFinalize() وبالتالى كدة هبقى متأكد أن الunmanged resources كدة كدة هيتم عمل clean لها

class UnManagedResources:IDisposable
    {
        //The garbage collector will call this destructor if the
        // object user forgets to call Dispose().
        ~UnManagedResources()
        {
            //Clean up unmanaged resources here.
        }

       public void Dispose()
        {
            //Clean up unmanaged resources here.
            
           //NO need to use finalize now 
            GC.SuppressFinalize();
           
        }
        //.......

}

وطبعا زى ما إحنا شايفين فى تكرار فى الكود حيث الfinalize تستخدم فقط للunmanaged resources أما الdispose ممكن تستخدم فى حالة الmanaged resources وبالتالى فى تلك الحالة هستخدم الFormalized Disposal pattern أو(Prim and proper disposal pattern ) حيث أنة قابل للتعديل وللصيانة

أنظر الى ذلك الكود

class UnManagedResources:IDisposable
    {
        //Used to determine if Dispose() has been already called
        private bool disposed = false;

        //The garbage collector will call this destructor if the
        // object user forgets to call Dispose().
        ~UnManagedResources()
        {
            //Call our helper method
            //Specifying 'false' signifies that GC triggered the clean up.
            CleanUp(false);
        }

       public void Dispose()
        {
            //Call our helper methods

            // Specifying "true" signifies that
            // the object user triggered the clean up.
            CleanUp(true);
            

           //NO need to use finalize now 
            GC.SuppressFinalize(this);
           
        }

        private void CleanUp(bool disposing)
        {
            //Be sure that we haven't already been dispoesed
            if (!this.disposed)
            {
                //if disposing  == true then dispose  all managed resources.
                if (disposing)
                {
                    //Dispose managed resources.
                }
                //clean up unmanaged resources.
            }

            disposed = true;
        }
        //.......
        }

Resurrection (الإحياء)

طبعا عرفنا سابقا أن الكائن الذى لم يعد لة أى إستخدام بيكون unreachable object يعنى كائن ميت على الرغم من أنة لو كان منتظر الfinalize method سيظل الكائن reachable يعنى حى حتى يتم مناداة الfinalize() وبالتالى يعتبر الكائن المنتظر الى الfinalize() عبارة عن

1-unreachable 2-reachable 3-unreachabel حيث كل خطوة من دول ناتجة من

1 من البرنامج يعنى من الApp root

2-من الfinalization queue حيث يعتبر المؤشر الموجود داخل الطابور وكأنة الroot لذلك الكائن

3-وجود الكائن داخل الfreachable queue ومنتظر مناداة الfinalize وتم عمل clean لة

حيث فائدة الResurrection رجوع الكائن من الunreachable الى reachable

عند وجود الكائن داخل الfreachabel queue ومنتظر مناداة الfinalize() ليتم تدميرة نهائيا فما بالك لو عند مناداة الfinalize يتم عمل مؤشر لذلك الكائن المراد تدميرة داخل static object كما موضح فى ذلك الكود

class BaseObj
    {
        ~BaseObj()
        {
            Application. ObjHolder = this;
            GC.ReRegisterForFinalize(this);
        }
    }
    class Application
    {
        public static object ObjHolder; //Default null.
    }

حيث عند تنفيذ الfinalize سيتم إنشاء root لذلك الكائن (this المراد إحيائة) عن طريق الObjHolder وبعد ذلك يتم مناداة الGC.ReRegisterForFinalize(object obj) حيث تعمل على وضع مؤشر لذلك الكائن (this ) داخل الfinalization queue وفى تلك الحالة تم تحويلة من unreachable الى reachable object أما فى حالة إكتشاف أن ذلك الكائن(this ) ليس لة أى إستخدام إذن يتم وضع لة مؤشر داخل الfreachable queue وبعد ذلك مناداة الfinalize() التىتعمل على إحياء ذلك الobject (this ) مرة أخرى.

حيث يفضل عدم إستخدام ال Resurrection بسبب تؤدى الى نتائج غير متوقعة (وصراحة أنا مش عارف عملية الاحياء دى تستخدم فى أية؟؟؟ )

Weak Reference

عندما الroot يشير الى الكائن وبالتالى الGC ميقدرش يعمل clean لذلك الكائن بسبب وجود root لة فى تلك الحالة يسمى بالStrong Reference to object وأيضا بما أن يوجد strong reference يوجد أيضا Weak Reference فى تلك الحالة ممكن الGC يعمل collect للكائن وبعد ذلك يتم إستخدامة مرة أخرى .

فى حالة أن الGC نيشط ووجد weak reference لكائن سيتم عمل collect لة عن طريق الGC

وبالتالى ليس متاح لنا إستخدام ذلك الكائن مرة أخرى إلا فى حالة تحويلة الى Strong reference كما سنرى

فائدة الWeak reference تستخدم للتقليل من الظغط الناتج من الكائنات الضخمة الموجودة داخل الManaged heap

مثال واقعى

على إفتراض عمل برنامج يستخدم لعرض جميع الdirectories and files on user's hard desk in simple tree

والمشكلة هنا أن الtree ممكن تكون كبيرة جدا وحاجزة مساحة كبيرة جدا من الذاكرة وعلى إفتراض أن المستخدم فى فترة إستخدامة للtree تركها وإستخدم جزء أخر من البرنامج وبالتالى لإحنا كدة عندنا waste space طب والحل أن إحنا نعمل delete للtree طب على أفتراض أن المستخدم حب يرجع مرة أخرى الى الtree هل هعيد نباء الtree مرة أخرى

الحل أن نستخدم الWeak Reference

فى حالة ان المستخدم ترك الtree وأشتغل بحاجة تانية فى البرنامج يتم عمل weak reference للtree وحذف جميع الstrong reference الخاصة بالtree . وفى حالة رجوع المستخدم مرة أخرى الى الtree يتم تحويل من weak reference الى strong reference ويتم إستخدامها مرة أخرى .

يحتوى الWeak reference class على two constructors كما موضح

WeakReference(object target)
WeakReference(object target,bool trackResurrectio)

حيث الtarget parameter يدل على الكائن المراد عمل weak reference لة أما الparameter الثانى وهو هل ذلك الكائن سيتم عمل لة weak reference بعد أم قبل إحياءة (رجوعة من الunreachable الى reachable ) حيث كما عنرفنا سابقا لا يفضل إستخدام ال Resurrection وبالتالى ذلك المتغير دائما بيكون بfalse وبالتالى دائما يتم إستخدام الfirst constructor

عند لإستخدام الconstructor التانى فى حالة إستخدامنا الResurrection operation يسمى بالlong weak reference أما فى الحالات الاخرى يسمى بshort weak reference

تعالى نشوف مثال بسيط

Void Method() {
   Object o = new Object();    // Creates a strong reference to the
                               // object.

   // Create a strong reference to a short WeakReference object.
   // The WeakReference object tracks the Object.
   WeakReference wr = new WeakReference(o);

   o = null;    // Remove the strong reference to the object

   o = wr.Target;
   if (o == null) {
      // A GC occurred and Object was reclaimed.
   } else {
      // a GC did not occur and we can successfully access the Object 
      // using o
   }
}

حيث عند إستخدام الكئن o مرة أخرى يتم التحويل من short weak reference الى strong reference عن طريق Target property وإرجاعها لroot بتاع ذلك الكائن

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

وبكدة يكون الدرس إنتهى ويارب تكونوا إستفدتوا وياريت لو فى أى أخطاء فى الشرح تفيدونا وأعتذر عن التطويل :)

تم تعديل هذه المشاركة بواسطة eng_3llam في 23 مارس 2006 في 23:13

Muhammad Allam

Computer Science

@Resource(MappedURL="My Blog" )

#3

بسم الله الرحمن الرحيم

جزاك الله عنا خيرا شرح اكثر من ممتاز ولكن انا مبتدىء ولا اعرف

عن ماذا تتكلم فلو تكرمت ممكن تقربلى المعنى شوية وخاصتة المعانى امثال

الGarbage collection الManaged heap الApplication root

ومن هذه المعانى

وللك جزيل الشكر اخى علام

وشكرا لقراءة رسالتى

والسلام عليكم ورحمة الله وبركاتة

#4
اقتباس
garbage collection

بالنسبة لعملية الMemory management(إدارة الذاكرة ) بتكون من مسئولية الcommon language runtime عن طريق ال

garbage collector

فى حالة أن أنا ممكن أتحكم فى تلك العملية عن طريق أستخدام class إسمة الGC (garbage collector الموجود داخل الSystem namespace حيث الGC يسهل حاجات كتير كانت مشاكل كبيرة مثلا

ممكن أنسى أعمل تدمير للكائن-أحاول أدمر acive object -أحاول أدمر الكائن أكثر من مرة حيث أغلب تلك المشاكل تقابل مبرمجى السى والسى بلس بلس -_-

اقتباس
Managed heap

بص علشان اوضحلك الفرق ألاول ما هو الstack

stack عبارة عن مجموعة من الصناديق الموضوعة فوق بعض لو حبيت أشيل إحدى الصناديق لازم أشيل اللى فوق ذلك الصندوق

أما الheap عبارة عن مجموعة من الصناديق الغير مرتبة كل صندوق موضوع فى مكان وهكذا

وبالتالى الmanaged heap عبارة عن مجموعة من المساحات العشوائية الموجودة داخل الذاكرة التى يتم التحكم بها عن طريق الCLR

حيث الGC يعتبر الHouse keeper للManaged heap :)

طب لية كلمة managed للدقة لا أكثر

كنا فى السى بلس بلس أو السى ممكن تتحكم فى الheap وتضع فية أى حجم من البيانات وبعد ذلك لتحرير تلك الذاكرة من البرنامج المستخدم لكى تعود الى الOS كنت أستخدم الkeyword====>delete ولكن كان يقابل المبمرج المشاكل السابقة وبالتالى سهلت علينا الدوت نت وخلت تلك العملية(عملية الreclaim للذاكرة) من نصيب ال.Net وليس المبرمج كل دة بيحصل عند إستخدام الManaged resources اللى يقدر الCLR ينظف الذاكرة منها أما فى حالة إستخدام الunmanaged resources كدوال الAPI

أو بعض الدوال المهام عن طريق الCOM

اقتباس
Application root

بص ياسيدى لو أنشاءت كائن ذلك الكائن يتم إرجاع عنوانة عن طريق الnew حيث الكائن وبياناتة موجودة داخل الmanaged heap

وعنوان لذلك الكائن موجود داخل الstack حيث المتغير الموجود داخل الstack يعتبر الroot لذلك الكائن الموجود بياناتة داخل الheap فى حالة عدم وجود ذلك المتغير يعتبر الكائن unreachable object .

وياريت لو تدخل على اللينكتين دول علشان تعرف ماهو الvalue type and reference type وما هو الheap

Reference types VS Value types Part I

Reference types VS value types Part II

أتمنى أن المفاهيم تكون وضحت وأكون أفدتك :)

تم تعديل هذه المشاركة بواسطة eng_3llam في 24 مارس 2006 في 15:45

Muhammad Allam

Computer Science

@Resource(MappedURL="My Blog" )

#5

من المواضيع الهامة التى أختفت بمرور الزمن !

لا إله إلا الله محمد رسول الله

アッラー以外に神はなし。ムハンマドはアッラーの使徒である

#6

الله ينور يا باشمهندس ،، تسلم ايدك

مواضيع مشابهة