رفع مشکلات حافظه

با نحوه استفاده از Chrome و DevTools برای یافتن مشکلات حافظه که بر عملکرد صفحه تأثیر می‌گذارند، از جمله نشت حافظه، نفخ حافظه و جمع‌آوری زباله مکرر بیاموزید.

خلاصه

  • با «مدیر وظیفه Chrome» ببینید صفحه شما چقدر از حافظه استفاده می کند.
  • با ضبط‌های Timeline، مصرف حافظه را در طول زمان تجسم کنید.
  • درخت‌های DOM جدا شده (یکی از دلایل رایج نشت حافظه) را با عکس‌های فوری Heap شناسایی کنید.
  • زمان تخصیص حافظه جدید در پشته JS خود را با ضبط های خط زمانی تخصیص پیدا کنید.
  • شناسایی عناصر جدا شده توسط مرجع جاوا اسکریپت.

نمای کلی

بر اساس روح مدل عملکرد RAIL ، تمرکز تلاش های عملکرد شما باید کاربران شما باشد.

مشکلات حافظه مهم هستند زیرا اغلب توسط کاربران قابل درک هستند. کاربران می توانند مشکلات حافظه را به روش های زیر درک کنند:

  • عملکرد یک صفحه به مرور زمان بدتر می شود. این احتمالاً نشانه ای از نشت حافظه است. نشت حافظه زمانی اتفاق می‌افتد که یک اشکال در صفحه باعث می‌شود صفحه به مرور زمان از حافظه بیشتری استفاده کند.
  • عملکرد یک صفحه به طور مداوم بد است. این احتمالاً یکی از علائم نفخ حافظه است. Memory bloat زمانی است که یک صفحه بیشتر از مقدار لازم برای سرعت صفحه بهینه از حافظه استفاده می کند.
  • عملکرد یک صفحه به تأخیر می افتد یا به نظر می رسد مکرراً متوقف می شود. این احتمالاً نشانه ای از جمع آوری زباله های مکرر است. جمع آوری زباله زمانی است که مرورگر حافظه را بازیابی می کند. مرورگر تصمیم می گیرد که چه زمانی این اتفاق بیفتد. در طول مجموعه ها، تمام اجرای اسکریپت متوقف می شود. بنابراین اگر مرورگر زباله‌های زیادی جمع‌آوری می‌کند، اجرای اسکریپت بسیار متوقف می‌شود.

نفخ حافظه: "خیلی زیاد" چقدر است؟

تعریف نشت حافظه آسان است. اگر سایتی به تدریج از حافظه بیشتر و بیشتری استفاده می کند، در این صورت شما نشت کرده اید. اما تشخیص نفخ حافظه کمی سخت تر است. چه چیزی به عنوان "استفاده از حافظه بیش از حد" واجد شرایط است؟

در اینجا اعداد سختی وجود ندارد، زیرا دستگاه ها و مرورگرهای مختلف قابلیت های متفاوتی دارند. همان صفحه‌ای که به‌راحتی در گوشی‌های هوشمند رده بالا اجرا می‌شود ممکن است در گوشی‌های هوشمند پایین‌رده از کار بیفتد.

نکته کلیدی در اینجا استفاده از مدل RAIL و تمرکز بر روی کاربران است. ببینید چه دستگاه هایی در بین کاربران شما محبوب هستند و سپس صفحه خود را در آن دستگاه ها آزمایش کنید. اگر تجربه به طور مداوم بد باشد، ممکن است صفحه از قابلیت‌های حافظه آن دستگاه‌ها بیشتر باشد.

با «مدیر وظیفه Chrome» استفاده از حافظه را به‌صورت بی‌درنگ نظارت کنید

از Chrome Task Manager به عنوان نقطه شروع برای بررسی مشکل حافظه خود استفاده کنید. Task Manager یک مانیتور بلادرنگ است که به شما می گوید یک صفحه چقدر حافظه مصرف می کند.

  1. Shift+Esc را فشار دهید یا به منوی اصلی Chrome بروید و More tools > Task manager را انتخاب کنید تا Task Manager باز شود.

    باز کردن Task Manager

  2. روی هدر جدول Task Manager کلیک راست کرده و حافظه جاوا اسکریپت را فعال کنید.

    فعال کردن حافظه JS در هدر Task manager.

این دو ستون به شما چیزهای مختلفی در مورد نحوه استفاده از حافظه صفحه شما می گویند:

  • ستون Memory footprint نشان دهنده حافظه سیستم عامل است. گره های DOM در حافظه سیستم عامل ذخیره می شوند. اگر این مقدار در حال افزایش باشد، گره های DOM ایجاد می شوند.
  • ستون حافظه جاوا اسکریپت نشان دهنده پشته JS است. این ستون شامل دو مقدار است. مقداری که به آن علاقه دارید، عدد زنده (عدد داخل پرانتز) است. عدد زنده نشان می‌دهد که اشیاء قابل دسترسی در صفحه شما چقدر از حافظه استفاده می‌کنند. اگر این تعداد در حال افزایش باشد، یا اشیاء جدید ایجاد می شوند یا اشیاء موجود در حال رشد هستند.

    Task Manager با هدر حافظه جاوا اسکریپت فعال است.

نشت حافظه را با ضبط‌های عملکرد تجسم کنید

همچنین می توانید از پنل عملکرد به عنوان نقطه شروع دیگری در تحقیقات خود استفاده کنید. پانل عملکرد به شما کمک می کند تا میزان استفاده از حافظه صفحه را در طول زمان تجسم کنید.

  1. پنل Performance را در DevTools باز کنید.
  2. کادر انتخاب Memory را فعال کنید.
  3. ضبط کنید .

برای نمایش عملکرد حافظه ضبط شده، کد زیر را در نظر بگیرید:

var x = [];

function grow() {
  for (var i = 0; i < 10000; i++) {
    document.body.appendChild(document.createElement('div'));
  }
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

هر بار که دکمه اشاره شده در کد فشار داده می شود، ده هزار گره div به بدنه سند اضافه می شود و رشته ای از یک میلیون کاراکتر x روی آرایه x فشار داده می شود. اجرای این کد یک ضبط خط زمانی مانند تصویر زیر ایجاد می کند:

یک مثال ساده رشد.

ابتدا توضیحی در مورد رابط کاربری. نمودار HEAP در پنجره Overview (زیر NET ) هیپ JS را نشان می دهد. در زیر پنجره Overview ، پنجره Counter قرار دارد. در اینجا می توانید میزان استفاده از حافظه را به تفکیک JS Heap (همانند نمودار HEAP در پنجره Overview )، اسناد، گره های DOM، شنوندگان و حافظه GPU مشاهده کنید. غیرفعال کردن یک چک باکس آن را از نمودار پنهان می کند.

اکنون، تجزیه و تحلیل کد در مقایسه با اسکرین شات. اگر به شمارنده گره (گراف سبز رنگ) نگاه کنید، می بینید که کاملاً با کد مطابقت دارد. تعداد گره ها در مراحل گسسته افزایش می یابد. شما می توانید فرض کنید که هر افزایش در تعداد گره ها یک فراخوانی برای grow() است. نمودار پشته JS (نمودار آبی) چندان ساده نیست. مطابق با بهترین شیوه ها، اولین شیب در واقع جمع آوری زباله اجباری است (با فشار دادن دکمه جمع آوری زباله به دست می آید). با پیشرفت ضبط، می توانید ببینید که اندازه پشته JS افزایش می یابد. این طبیعی و قابل انتظار است: کد جاوا اسکریپت گره‌های DOM را در هر کلیک روی دکمه ایجاد می‌کند و وقتی رشته‌ای از یک میلیون کاراکتر ایجاد می‌کند، کارهای زیادی انجام می‌دهد. نکته کلیدی در اینجا این واقعیت است که پشته JS بالاتر از آنچه که شروع شده به پایان می رسد («شروع» در اینجا نقطه پس از جمع آوری اجباری زباله است). در دنیای واقعی، اگر این الگوی افزایش اندازه پشته JS یا اندازه گره را مشاهده کردید، به طور بالقوه به معنای نشت حافظه است.

با Heap Snapshots، نشت حافظه درخت DOM جدا شده را کشف کنید

یک گره DOM فقط زمانی می تواند زباله جمع آوری شود که هیچ ارجاعی به آن از درخت DOM صفحه یا کد جاوا اسکریپت وجود نداشته باشد. گفته می شود که یک گره زمانی که از درخت DOM حذف می شود "جدا" می شود اما برخی جاوا اسکریپت هنوز به آن ارجاع می دهد. گره های DOM جدا شده یکی از دلایل شایع نشت حافظه هستند. این بخش به شما می آموزد که چگونه از Heap profilers DevTools برای شناسایی گره های جدا شده استفاده کنید.

در اینجا یک مثال ساده از گره های DOM جدا شده آورده شده است.

var detachedTree;

function create() {
  var ul = document.createElement('ul');
  for (var i = 0; i < 10; i++) {
    var li = document.createElement('li');
    ul.appendChild(li);
  }
  detachedTree = ul;
}

document.getElementById('create').addEventListener('click', create);

با کلیک بر روی دکمه اشاره شده در کد، یک گره ul با ده فرزند li ایجاد می شود. این گره ها توسط کد ارجاع می شوند اما در درخت DOM وجود ندارند، بنابراین جدا می شوند.

عکس های فوری هیپ یکی از راه های شناسایی گره های جدا شده است. همانطور که از نام آن پیداست، عکس‌های فوری به شما نشان می‌دهند که چگونه حافظه بین اشیاء JS و گره‌های DOM صفحه شما در نقطه زمانی عکس فوری توزیع می‌شود.

برای ایجاد یک عکس فوری، DevTools را باز کنید و به پنل حافظه بروید، دکمه رادیویی Heap Snapshot را انتخاب کنید و سپس دکمه Take snapshot را فشار دهید.

دکمه رادیویی Heap Snapshot انتخاب شده است.

پردازش و بارگیری عکس فوری ممکن است کمی طول بکشد. پس از پایان کار، آن را از پانل سمت چپ (به نام عکس های فوری Heap ) انتخاب کنید.

برای جستجوی درخت‌های DOM جداشده، Detached در کادر ورودی فیلتر کلاس تایپ کنید.

فیلتر کردن گره های جدا شده

قیراط ها را گسترش دهید تا درخت جدا شده را بررسی کنید.

بررسی درخت جدا شده

برای بررسی بیشتر روی یک گره کلیک کنید. در قسمت Objects می‌توانید اطلاعات بیشتری درباره کدی که به آن ارجاع می‌دهد، ببینید. به عنوان مثال، در تصویر زیر می توانید ببینید که متغیر detachedTree به گره ارجاع می دهد. برای رفع این نشت حافظه خاص، باید کدی را مطالعه کنید که از detachedTree استفاده می کند و اطمینان حاصل کنید که ارجاع آن به گره را زمانی که دیگر نیازی به آن نیست حذف می کند.

بررسی یک گره جدا شده

نشت حافظه پشته JS را با Timelines تخصیص شناسایی کنید

Allocation Timeline ابزار دیگری است که می تواند به شما کمک کند نشت حافظه را در پشته JS خود ردیابی کنید.

برای نشان دادن جدول زمانی تخصیص کد زیر را در نظر بگیرید:

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

هر بار که دکمه اشاره شده در کد فشار داده می شود، رشته ای از یک میلیون کاراکتر به آرایه x اضافه می شود.

برای ضبط یک خط زمانی تخصیص ، DevTools را باز کنید، به پانل حافظه بروید، دکمه رادیویی Allocations on timeline را انتخاب کنید، دکمه Record را فشار دهید، عملی را انجام دهید که گمان می‌کنید باعث نشت حافظه شده است، و سپس دکمه را فشار دهید. دکمه توقف ضبط پس از اتمام کار.

همانطور که در حال ضبط هستید، توجه کنید که آیا هر نوار آبی در جدول زمانی تخصیص ظاهر می شود، مانند تصویر صفحه زیر.

تخصیص های جدید در جدول زمانی عملکرد.

آن نوارهای آبی نشان دهنده تخصیص حافظه جدید است. این تخصیص حافظه جدید، کاندیدای شما برای نشت حافظه هستند. می‌توانید روی یک نوار بزرگ‌نمایی کنید تا پنجره Constructor را فیلتر کنید تا فقط اشیایی را نشان دهید که در بازه زمانی مشخص شده تخصیص داده شده‌اند.

جدول زمانی تخصیص بزرگنمایی شده

شی را باز کنید و روی مقدار آن کلیک کنید تا جزئیات بیشتری در مورد آن در صفحه Object مشاهده کنید. به عنوان مثال، در تصویر زیر، با مشاهده جزئیات شی ای که به تازگی اختصاص داده شده است، می توانید ببینید که به متغیر x در محدوده Window اختصاص یافته است.

جزئیات شیء یک آرایه رشته ای.

تخصیص حافظه بر اساس تابع را بررسی کنید

از نوع نمایه نمونه برداری تخصیص در پانل حافظه برای مشاهده تخصیص حافظه توسط تابع جاوا اسکریپت استفاده کنید.

نمایه ساز نمونه برداری تخصیص در پانل حافظه.

  1. دکمه رادیویی Allocation sampling را انتخاب کنید. اگر کارگری در صفحه وجود دارد، می توانید آن را به عنوان هدف نمایه سازی از پنجره نمونه انتخاب جاوا اسکریپت VM انتخاب کنید.
  2. دکمه Start را فشار دهید.
  3. اقدامات را در صفحه ای که می خواهید بررسی کنید انجام دهید.
  4. هنگامی که تمام اقدامات خود را به پایان رساندید، دکمه Stop را فشار دهید.

DevTools تفکیک تخصیص حافظه بر اساس عملکرد را به شما نشان می دهد. نمای پیش فرض Heavy (از پایین به بالا) است که عملکردهایی را که بیشترین حافظه را به خود اختصاص داده اند در بالا نمایش می دهد.

صفحه نتایج نمایه تخصیص.

اشیاء حفظ شده توسط مرجع JS را شناسایی کنید

نمایه عناصر جدا شده به شما عناصر جدا شده را نشان می دهد که باقی می مانند زیرا با کد جاوا اسکریپت ارجاع می شوند.

برای مشاهده گره های HTML و تعداد گره ها، نمایه عناصر جدا شده را ضبط کنید.

نمونه پروفایل عناصر جدا شده

جمع آوری زباله های مکرر را مشاهده کنید

اگر به نظر می رسد که صفحه شما مکرراً مکث می کند، ممکن است مشکلات جمع آوری زباله داشته باشید.

می‌توانید از «مدیریت وظایف Chrome» یا ضبط‌های حافظه «خط زمان» برای شناسایی زباله‌های مکرر استفاده کنید. در Task Manager، مقادیر مکرر افزایش و کاهش حافظه یا جاوا اسکریپت حافظه نشان دهنده مجموعه زباله های مکرر هستند. در ضبط‌های تایم لاین، نمودارهای شمارش گره یا هیپ JS مکرر بالا و پایین می‌روند که نشان‌دهنده جمع‌آوری زباله‌های مکرر است.

هنگامی که مشکل را شناسایی کردید، می توانید از ضبط جدول زمانی تخصیص استفاده کنید تا متوجه شوید که حافظه در کجا تخصیص می یابد و کدام توابع باعث تخصیص می شوند.