اجمع نفاياتك من فضلك - إدارة الذاكرة في جافاسكريبت

كتبت بواسطة Basel Issmail | بتاريخ الثلاثاء 31 اذار 2020

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

سبب هذه الظاهرة هي وجود تسرب في الذاكرة ضمن صفحة الويب مما أدى إلى نفاذ الذاكرة المتاحة.


لغات البرمجة منخفضة المستوى مثل C، تكون إدارة الذاكرة يدوية باستخدام الدوال free و malloc، بينما في المقابل، تقوم لغة البرمجة جافاسكريبت بتخصيص الذاكرة تلقائيًا عند إنشاء الأغراض "Objects"، وتحريرها عند الانتهاء من استخدامها (جامع النفايات) garbage collector.

هذه التلقائية هي مصدر محتمل للارتباك: يمكن أن تعطي المطورين انطباعًا خاطئًا بأنهم لا يحتاجون إلى القلق بشأن إدارة الذاكرة.


دورة حياة الذاكرة:

بغض النظر عن لغة البرمجة، فإن دورة حياة الذاكرة هي نفسها دائمًا:


1- تخصيص الذاكرة التي تحتاجها

2- استخدام الذاكرة المخصصة (القراءة والكتابة)

3- تحرير الذاكرة المخصصة عندما لا تكون هناك حاجة إليها بعد الآن


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


ما معنى تسرب الذاكرة؟

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


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

يقوم "جامع النفايات" بمتابعة أجزاء الذاكرة التي تم تخصيصها، وعندما تصبح هذه الأجزاء غير قابلة للوصول اليها، يقوم المجمع بتحريرها. 

المعضلة الأساسية متمثلة في معرفة ما إذا كانت بعض أجزاء الذاكرة لم يعد هناك حاجة إليها حيث انها غير قابلة للتحديد من قبل "جامع النفايات"، لذا يُترك القرار للمطور بتحديد إن كانت هذه الذواكر بحاجتها أو لا.

والسبب الرئيسي لحدوث تسرب في الذاكرة هي المراجع "references" الغير مرغوب بها، مثل المتحولات العامة "global variables" تعليمات interval منسية، وعناصر DOM المنفصلة.


حسناً، لكن كيف يمكنني أن أكتشف تسرباً في الذاكرة بحال وجودها؟

سأقوم باستخدام المثال في الرابط 

من الطرق الممكنة لاكتشاف التسرب هي من خلال أدوات المطور devtools، باتباع الخطوات التالية:

1- افتح أدوات المطور من خلال النقر على F12 او ctrl + shift + i

2- انتقل إلى تبويبة performance 

3- انقر على أيقونة التسجيل

4- اتركها لمدة لا تقل عن 10 ثواني وأثناء التسجيل يمكن النقر على أيقونة سلة القمامة عدة مرات ليبدأ "جامع النفايات" العمل.



بعد انتهاء المعالجة وظهور النتائج، بإمكانك تحليلها بالشكل التالي:

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


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


كيف يمكننا معرفة موضع المشكلة، وحلها؟

هنالك العديد من الطرق لاكتشاف مواضع وسبب تسرب الذاكرة، إحداها هو التالي:

1- افتح أدوات المطور من خلال النقر على F12 او ctrl + shift + i

2- انتقل إلى تبويبة memory 

3- انقر على أيقونة التسجيل لأخذ عينة من حجم الذاكرة الحالي

4- بعد فترة من الزمن قم بالنقر مجددا عليها

5- اختر summary وضمنها compare


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


بالعودة إلى مثالنا السابق وتطبيق الخطوات عليه، يمكننا ملاحظة تغير في حجم (concatenated string)  وأن التغير في النص يشير إلى المتحول x.


كما نلحظ زيادة كبير في عناصر ال DOM، ومن خلال وضع المؤشر على إحداها، يعطينا معلومات وافية عن تفاصيل هذا العنصر.


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