1. آلية إعادة تدوير القمامة - GC
لدى JavaScript آلية جمع القمامة التلقائي (GC: Collection Garbage) ، مما يعني أن بيئة التنفيذ مسؤولة عن إدارة الذاكرة المستخدمة أثناء تنفيذ التعليمات البرمجية.
المبدأ: يجد جامع القمامة بشكل دوري (دوري) متغيرات غير مستخدمة ثم يحرر ذاكرتها.
آلية مجموعة JavaScript Garbage بسيطة للغاية: اكتشف المتغيرات التي لم تعد تستخدم ثم تحرير الذاكرة التي تشغلها. ومع ذلك ، فإن هذه العملية ليست في الوقت الفعلي لأن النفقات العامة كبيرة نسبيًا ، لذلك سيتم تنفيذ جامع القمامة بشكل دوري على فترات زمنية ثابتة .
المتغيرات التي لم تعد تستخدم هي متغيرات تنهي دورة الحياة. بالطبع ، يمكن أن تكون متغيرات محلية فقط. لن تنتهي دورة حياة المتغير العالمي حتى يقوم المتصفح بإلغاء تثبيت الصفحة. توجد المتغيرات المحلية فقط أثناء تنفيذ الوظيفة ، وفي هذه العملية ، سيتم تخصيص المساحة المقابلة للمتغيرات المحلية على المكدس أو الكومة لتخزين قيمها ، ثم يتم استخدام هذه المتغيرات في الوظيفة حتى نهاية الوظيفة. ومع ذلك ، بسبب الوظائف الداخلية في الإغلاق ، لا يمكن اعتبار الوظائف الخارجية تنتهي.
دعنا فقط نشرح الرمز:
الدالة fn1 () {var obj = {name: 'hanzichi' ، العمر: 10} ؛} الدالة fn2 () {var obj = {name: 'hanzichi' ، العمر: 10} ؛ إرجاع OBJ ؛} var a = fn1 () ؛ var b = fn2 () ؛دعونا نرى كيف يتم تنفيذ الرمز. أولاً ، يتم تعريف وظيفتين ، تسمى FN1 و FN2. عندما يتم استدعاء FN1 ، سيفتح إدخال بيئة FN1 كائن تخزين الذاكرة {name: 'Hanzichi' ، العمر: 10}. عند الانتهاء من المكالمة وبيئة FN1 خارج ، سيتم إصدار كتلة الذاكرة تلقائيًا بواسطة جامع القمامة في محرك JS ؛ أثناء عملية استدعاء FN2 ، يتم الإشارة إلى الكائن الذي تم إرجاعه بواسطة المتغير العالمي B ، وبالتالي لن يتم إصدار كتلة الذاكرة.
هنا يطرح السؤال: أي متغير لا طائل منه؟ لذلك ، يجب على جامع القمامة تتبع المتغير الذي لا طائل منه والمتغيرات التي لم تعد مفيدة من أجل استعادة ذاكرته في المستقبل. قد تختلف استراتيجيات المتغيرات غير المجدية المستخدمة للعلامة عن طريق التنفيذ ، وعادة ما تكون هناك طريقتان للقيام بذلك: مارك خلوص والعد المرجعي. عدد الاقتباس ليس شائعًا جدًا ، يتم استخدام تطهير العلامات بشكل أكثر شيوعًا.
2. علامة واضحة
طريقة جمع القمامة الأكثر استخدامًا في JS هي إزالة علامة. عندما يدخل المتغير إلى البيئة ، على سبيل المثال ، يعلن عن متغير في دالة ما ، فإنه يمثل المتغير على أنه "أدخل البيئة". من الناحية المنطقية ، لا يمكن إطلاق الذاكرة التي تشغلها المتغيرات التي تدخل البيئة ، لأنه يمكن استخدامها طالما أن تدفق التنفيذ يدخل البيئة المقابلة. وعندما يترك المتغير البيئة ، يتم تمييزه على أنه "خارج البيئة".
دالة اختبار () {var a = 10 ؛ // مميز ، أدخل البيئة var b = 20 ؛ // تم وضع علامة ، أدخل البيئة} test () ؛ // بعد التنفيذ ، يتم وضع علامة A و B ، وترك البيئة ويتم إعادة تدويرها.عندما يعمل جامع القمامة ، فإنه يمثل جميع المتغيرات المخزنة في الذاكرة (بالطبع ، يمكن استخدام أي طريقة وضع علامة). ثم يزيل علامات (إغلاق) المتغيرات في البيئة والمتغيرات المشار إليها من قبل المتغيرات في البيئة. سيتم اعتبار المتغيرات المحددة بعد ذلك متغيرات جاهزة للحذف لأن المتغيرات في البيئة لم تعد قادرة على الوصول إلى هذه المتغيرات. أخيرًا ، يكمل جامع القمامة أعمال تطهير الذاكرة ، وتدمير تلك القيم المميزة واستعادة مساحة الذاكرة التي يشغلونها.
حتى الآن ، تستخدم تطبيقات JS لـ IE و Firefox و Opera و Chrome و Safari استراتيجيات جمع القمامة أو الاستراتيجيات المماثلة ، ولكن الفواصل الزمنية لجمع القمامة تختلف عن بعضها البعض.
3. عدد اقتباس
معنى العد المرجعي هو تتبع عدد المرات التي تتم الإشارة إلى كل قيمة. عندما يتم الإعلان عن متغير وتعيين قيمة نوع المرجع للمتغير ، فإن عدد المراجع إلى هذه القيمة هو 1. إذا تم تعيين نفس القيمة لمتغير آخر ، فإن عدد المراجع إلى القيمة يتم زيادة بالقيمة بمقدار 1. يمكن استرداد المساحة التي تحتلها. بهذه الطريقة ، عندما يعمل جامع القمامة مرة أخرى في المرة القادمة ، فإنه يحرر الذاكرة التي تقدر مع 0 مراجع.
دالة اختبار () {var a = {} ؛ // عدد مراجع A هو 0 var b = a ؛ // عدد مراجع A هو 1 var c = a ؛ // عدد مراجع A هو 1 ، وعدد مراجع A هو 1 ، وعدد مراجع A هو 1 ، وعدد مراجع A هو 2 var B = {} ؛ // عدد مراجع A هو 1 ، وعدد مراجع A هو 1}كان Netscape Navigator3 أول متصفح يستخدم استراتيجية العد المرجعية ، ولكن سرعان ما واجه مشكلة خطيرة: المراجع الدائرية. يشير مرجع دائري إلى كائن A يحتوي على مؤشر إلى الكائن B ، ويحتوي الكائن B أيضًا على مرجع إلى كائن A.
الدالة fn () {var a = {} ؛ var b = {} ؛ A.Pro = B ؛ B.Pro = a ؛} fn () ؛الأوقات المرجعية لـ A و B أعلاه هي 2. بعد تنفيذ FN () ، ترك كلا الكائنين البيئة. لا توجد مشكلة في وضع المقاصة. ومع ذلك ، بموجب استراتيجية العد المرجعية ، نظرًا لأن أوقات المرجع لـ A و B ليست 0 ، فلن يتم جمع الذاكرة بواسطة جامع القمامة. إذا تم استدعاء وظيفة FN بكميات كبيرة ، فسيحدث تسرب الذاكرة. على IE7 و IE8 ، ترتفع الذاكرة بشكل حاد.
نحن نعلم أن بعض الأشياء في IE ليست كائنات JS الأصلية. على سبيل المثال ، يتم تنفيذ الكائنات الموجودة في DOM و BOM في شكل كائنات COM باستخدام C ++ ، وآلية جمع القمامة الخاصة بكائنات COM تعتمد استراتيجية حساب مرجعية. لذلك ، حتى إذا كان محرك IE JS يتبنى استراتيجية لتطهير العلامات ، فإن كائنات COM التي تم الوصول إليها من قبل JS لا تزال تستند إلى استراتيجية العد المرجعية. بمعنى آخر ، طالما أن كائنات com متورطة في IE ، ستكون هناك مشكلة في المراجع الدائرية.
var element = document.getElementById ("some_element") ؛ var myobject = new Object () ؛ myobject.e = element ؛ element.o = myObject ؛ينشئ هذا المثال مرجعًا دائريًا بين عنصر DOM وكائن JS الأصلي. من بينها ، يحتوي MyObject المتغير على سمة مسماة عنصر يشير إلى كائن العنصر ؛ والعنصر المتغير يحتوي أيضًا على سمة تسمى O مرة أخرى للإشارة إلى myobject. بسبب هذا المرجع الدائري ، حتى إذا تمت إزالة DOM في المثال من الصفحة ، فلن يتم إعادة تدويره أبدًا.
بالنظر إلى المثال أعلاه ، اعتقد بعض الطلاب أنه كان ضعيفًا جدًا. من سيفعل مثل هذا الشيء الممل؟ في الواقع ، هل نفعل ذلك؟
window.onload = function OuterFunction () {var obj = document.getElementById ("element") ؛ obj.onclick = function innerfunction () {} ؛} ؛يبدو أن هذا الرمز على ما يرام ، لكن OBJ يشير إلى document.getElementById ("العنصر") ، وسيشير طريقة OnClick الخاصة بـ document.getElementById ("element") إلى المتغير الألماني في البيئة الخارجية ، والتي تتضمن أيضًا OBJ أيضًا. أليست مخفية جدا؟
حل
أسهل طريقة هي عدم تدفق الحلقة يدويًا ، على سبيل المثال ، يمكن للوظيفة الآن القيام بذلك.
myobject.element = null ؛ element.o = null ؛
window.onload = function OuterFunction () {var obj = document.getElementById ("element") ؛ obj.onclick = function innerfunction () {} ؛ obj = null ؛} ؛يعني تعيين متغير إلى NULL قطع الاتصال بين المتغير والقيمة التي تمت الإشارة إليها مسبقًا. عندما يعمل جامع القمامة في المرة القادمة ، يتم حذف هذه القيم ويتم إعادة تدوير الذاكرة التي تشغلها.
تجدر الإشارة إلى أن IE9+ ليس لديه مرجع دائري للتسبب في تسرب ذاكرة DOM. قد تكون Microsoft قد قمت بتحسينه ، أو تغيرت طريقة إعادة التدوير في DOM.
4. إدارة الذاكرة
1. متى سيتم تشغيل جمع القمامة؟
يعمل جامع القمامة بشكل دوري. إذا كانت الذاكرة المخصصة كبيرة جدًا ، فسيكون عمل إعادة التدوير صعبًا للغاية. يصبح تحديد فترة زمنية جمع القمامة سؤالًا يستحق التفكير فيه. تعمل مجموعة القمامة IE6 وفقًا لتخصيص الذاكرة. عندما يكون هناك 256 متغيرًا ، و 4096 كائنًا ، وسلاسل 64 ألفًا في البيئة ، سيتم تشغيل جامع القمامة. تبدو علمية للغاية ولا تحتاج إلى استدعاء مرة واحدة لفترة من الوقت. في بعض الأحيان يكون غير ضروري. أليس من الجيد استدعاء الطلب مثل هذا؟ ولكن إذا كان هناك العديد من المتغيرات في البيئة ، وكانت البرامج النصية معقدة وعادية للغاية الآن ، فإن النتيجة هي أن جامع القمامة يعمل دائمًا ، لذلك لا يمكن للمتصفح اللعب.
قامت Microsoft بإجراء تعديلات في IE7. لم تعد ظروف الزناد ثابتة ، ولكن تم تعديلها ديناميكيًا. القيمة الأولية هي نفسها مثل IE6. إذا كان تخصيص الذاكرة الذي تم جمعه بواسطة جامع القمامة أقل من 15 ٪ من الذاكرة التي يشغلها البرنامج ، فهذا يعني أنه لا يمكن إعادة تدوير معظم الذاكرة. تعد ظروف تشغيل مجموعة مجموعة القمامة حساسة للغاية. في هذا الوقت ، مضاعفة ظروف الشارع. إذا كانت الذاكرة التي تم جمعها أعلى من 85 ٪ ، فهذا يعني أنه يجب تنظيف معظم الذاكرة منذ فترة طويلة. في هذا الوقت ، يتم تعيين ظروف الزناد. هذا يجعل عمل إعادة تدوير القمامة المزيد من الوظائف
2. حل GC معقول
1) حل GC الأساسي لمحرك JavaScript هو (GC بسيط): Mark and Sweep ، أي:
2) عيوب GC
مثل اللغات الأخرى ، لا يمكن لسياسة GC الخاصة بـ JavaScript تجنب مشكلة واحدة: عند GC ، توقف عن الاستجابة للعمليات الأخرى ، وهو لأسباب أمنية. GC من JavaScript هو 100 مللي ثانية أو حتى أعلى ، وهو أمر جيد للتطبيقات العامة ، ولكن بالنسبة لألعاب JS ، فإن التطبيقات التي تتطلب التماسك العالي مزعجة. هذا هو ما يحتاجه المحرك الجديد لتحسينه: تجنب الاستجابة طويلة الأجل التي تسببها GC.
3) استراتيجية تحسين GC
قدم العم ديفيد حليتين تحسين ، وهناك أيضًا أهم حللين للتحسين:
(1) جيل GC)
وهذا يتفق مع فكرة استراتيجية إعادة تدوير Java. والغرض من ذلك هو التمييز بين الأشياء "المؤقتة" و "المستمرة" ؛ قم بإعادة تدوير المزيد من مناطق "الكائن المؤقت" وأقل "كائن" مُثبّت "، وتقليل الكائنات التي تحتاج إلى اجتياز في كل مرة ، وبالتالي تقليل الوقت الذي تقضيه على GCS في كل مرة. كما هو موضح في الصورة:
ما يجب إضافته هنا هو أنه بالنسبة لكائن الجيل المُثنّع ، هناك تكاليف إضافية: ترحيله من الجيل الشاب إلى الجيل المصلح ، وإذا تمت الإشارة إليه ، فيجب تعديل الإشارة المرجعية أيضًا.
(2) GC الإضافي
فكرة هذه الخطة بسيطة للغاية ، وهي "معالجة قليلاً في كل مرة ، والتعامل مع بعض الوقت في المرة القادمة ، وما إلى ذلك." كما هو موضح في الصورة:
على الرغم من أن هذا الحل يستغرق وقتًا قصيرًا ، إلا أنه يحتوي على العديد من الانقطاعات ، مما يجلب مشكلة تبديل السياق المتكرر.
نظرًا لأن كل حل له سيناريوهات وعيوب قابلة للتطبيق ، في التطبيقات الفعلية ، سيتم اختيار الحل وفقًا للوضع الفعلي.
على سبيل المثال: عندما تكون نسبة (الكائن/s) منخفضة ، يتم مقاطعة تواتر تنفيذ GC ، و GC البسيط أقل ؛ إذا كانت هناك عدد كبير من الكائنات "نجا" لفترة طويلة ، فإن ميزة معالجة الأجيال ليست رائعة.
إن المقالة أعلاه تتفهم بشكل شامل آلية إعادة تدوير جمع القمامة Javascirp هي كل المحتوى الذي أشاركه معك. آمل أن يعطيك مرجعًا وآمل أن تتمكن من دعم wulin.com أكثر.