عکس‌های فوری پشته‌ای را ضبط کنید

مگین کرنی
Meggin Kearney
سوفیا املیانوا
Sofia Emelianova

یاد بگیرید که چگونه عکس های فوری پشته ای را با Memory > Profiles > Heap snapshot ضبط کنید و نشت حافظه را پیدا کنید.

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

یک عکس فوری بگیرید

برای گرفتن عکس فوری پشته ای:

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

یک نوع پروفایل انتخاب شده و نمونه جاوا اسکریپت VM.

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

اندازه کل اشیاء قابل دسترسی

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

عکس فوری پشته ای از اشیاء پراکنده مورد.

پاک کردن عکس های فوری

برای حذف همه عکس‌های فوری، پاک کردن تمام نمایه‌ها کلیک کنید:

تمام پروفایل ها را پاک کنید

مشاهده عکس های فوری

برای بررسی عکس‌های فوری از منظرهای مختلف برای اهداف مختلف، یکی از نماها را از منوی کشویی در بالا انتخاب کنید:

مشاهده کنید محتوا هدف
خلاصه اشیاء گروه بندی شده بر اساس نام سازنده از آن برای شکار اشیا و استفاده از حافظه آنها بر اساس نوع استفاده کنید. برای ردیابی نشت DOM مفید است.
مقایسه تفاوت بین دو عکس فوری از آن برای مقایسه دو (یا بیشتر) عکس فوری، قبل و بعد از عملیات استفاده کنید. وجود و علت نشت حافظه را با بررسی دلتا در حافظه آزاد شده و تعداد مرجع تأیید کنید.
مهار محتویات پشته دید بهتری از ساختار شی ارائه می دهد و به تجزیه و تحلیل اشیاء ارجاع شده در فضای نام جهانی (پنجره) برای یافتن آنچه آنها را در اطراف نگه می دارد کمک می کند. از آن برای تجزیه و تحلیل بسته ها و شیرجه رفتن در اشیاء خود در سطح پایین استفاده کنید.
آمار نمودار دایره ای تخصیص حافظه اندازه واقعی قطعات حافظه اختصاص داده شده به کد، رشته ها، آرایه های JS، آرایه های تایپ شده و اشیاء سیستم را ببینید.

نمای خلاصه از منوی کشویی در بالا انتخاب شده است.

نمای خلاصه

در ابتدا، یک عکس فوری پشته ای در نمای Summary باز می شود که سازنده ها را در یک ستون لیست می کند. می‌توانید سازنده‌ها را گسترش دهید تا اشیایی را که نمونه‌سازی کرده‌اند ببینید.

نمای خلاصه با سازنده توسعه یافته.

برای فیلتر کردن سازنده‌های نامربوط، نامی را که می‌خواهید در فیلتر کلاس در بالای نمای Summary بررسی کنید تایپ کنید.

اعداد کنار نام سازنده تعداد کل اشیاء ایجاد شده با سازنده را نشان می دهد. نمای Summary نیز ستون های زیر را نشان می دهد:

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

وقتی یک سازنده را گسترش می دهید، نمای Summary تمام نمونه های آن را به شما نشان می دهد. هر نمونه تفکیک اندازه های کم عمق و حفظ شده خود را در ستون های مربوطه دریافت می کند. شماره بعد از کاراکتر @ شناسه منحصر به فرد شی است. این به شما امکان می دهد عکس های فوری پشته ای را بر اساس هر شی مقایسه کنید.

فیلترهای سازنده

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

برای استفاده از این فیلترها، یکی از گزینه های زیر را از سمت راست ترین منوی کشویی در نوار عمل انتخاب کنید:

  • همه اشیاء : همه اشیاء گرفته شده توسط عکس فوری فعلی. به صورت پیش فرض تنظیم شود.
  • اشیاء تخصیص داده شده قبل از عکس فوری 1 : اشیایی که قبل از گرفتن اولین عکس فوری ایجاد شده و در حافظه باقی مانده اند.
  • اشیاء تخصیص یافته بین عکس فوری 1 و عکس فوری 2 : مشاهده تفاوت در اشیاء بین جدیدترین عکس فوری و عکس فوری قبلی. هر عکس فوری جدید یک افزایش از این فیلتر را به لیست کشویی اضافه می کند.
  • رشته های تکراری : مقادیر رشته ای که چندین بار در حافظه ذخیره شده اند.
  • اشیاء حفظ شده توسط گره های جدا شده : اشیایی که زنده نگه داشته می شوند زیرا یک گره DOM جدا شده به آنها ارجاع می دهد.
  • اشیاء حفظ شده توسط کنسول DevTools : اشیایی که در حافظه نگهداری می شوند زیرا از طریق کنسول DevTools ارزیابی شده یا با آنها تعامل داشته اند.

نوشته های ویژه در خلاصه

علاوه بر گروه بندی توسط سازنده، نمای Summary نیز اشیاء را بر اساس:

  • توابع داخلی مانند Array یا Object .
  • عناصر HTML با تگ های خود گروه بندی می شوند، به عنوان مثال، <div> ، <a> ، <img> ، و دیگران.
  • توابعی که در کد خود تعریف کرده اید.
  • دسته بندی های خاصی که بر اساس سازنده نیستند.

ورودی های سازنده

(array)

این دسته شامل اشیاء آرایه مانند داخلی مختلفی است که مستقیماً با اشیاء قابل مشاهده در جاوا اسکریپت مطابقت ندارند.

به عنوان مثال، محتویات اشیاء Array جاوا اسکریپت در یک شی داخلی ثانویه به نام (object elements)[] ذخیره می‌شوند تا امکان تغییر اندازه آسان‌تر را فراهم کنند. به طور مشابه، ویژگی های نامگذاری شده در اشیاء جاوا اسکریپت اغلب در اشیاء داخلی ثانویه به نام (object properties)[] که در دسته (array) نیز فهرست شده اند، ذخیره می شوند.

(compiled code)

این دسته شامل داده های داخلی است که V8 به آن نیاز دارد تا بتواند توابع تعریف شده توسط JavaScript یا WebAssembly را اجرا کند. هر تابع را می توان به روش های مختلفی نشان داد، از کوچک و آهسته تا بزرگ و سریع.

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

(concatenated string)

هنگامی که V8 دو رشته را به هم متصل می کند، مانند عملگر JavaScript + ، ممکن است انتخاب کند که نتیجه را به صورت یک "رشته پیوسته" که به نام ساختار داده Rope نیز شناخته می شود، نمایش دهد.

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

InternalNode

این دسته اشیاء تخصیص داده شده خارج از V8 را نشان می دهد، مانند اشیاء C++ که توسط Blink تعریف شده اند.

برای دیدن نام کلاس های C++، از Chrome for Testing استفاده کنید و موارد زیر را انجام دهید:

  1. DevTools را باز کنید و > آزمایش‌ها > گزینه Show را روشن کنید تا موارد داخلی در عکس‌های فوری انبوه نمایش داده شود.
  2. پانل حافظه را باز کنید، Heap snapshot را انتخاب کنید و Expose interiors (شامل جزئیات بیشتر مربوط به پیاده سازی) را روشن کنید.
  3. مشکلی را که باعث شد InternalNode حافظه زیادی را حفظ کند، دوباره تولید کنید.
  4. یک عکس فوری پشته بگیرید. در این عکس فوری، اشیاء به جای InternalNode دارای نام کلاس C++ هستند.
(object shape)

همانطور که در Fast Properties در V8 توضیح داده شد، V8 کلاس‌ها (یا اشکال ) پنهان را ردیابی می‌کند تا چندین شی با ویژگی‌های یکسان به ترتیب یکسان بتوانند به طور کارآمد نمایش داده شوند. این دسته شامل کلاس‌های مخفی به نام system / Map (غیر مرتبط با Map جاوا اسکریپت) و داده‌های مرتبط است.

(sliced string)

زمانی که V8 نیاز به گرفتن یک رشته فرعی دارد، مانند زمانی که کد جاوا اسکریپت String.prototype.substring() را فرا می خواند، V8 ممکن است به جای کپی کردن همه کاراکترهای مرتبط از رشته اصلی، یک شی رشته برش داده شده را اختصاص دهد. این شی جدید حاوی یک اشاره گر به رشته اصلی است و توصیف می کند که از کدام محدوده از کاراکترهای رشته اصلی استفاده شود.

از منظر کدهای جاوا اسکریپت، اینها فقط رشته های معمولی هستند و مانند هر رشته دیگری رفتار می کنند. اگر یک رشته برش‌شده حافظه زیادی را حفظ کند، ممکن است برنامه شماره ۲۸۶۹ را راه‌اندازی کرده باشد و ممکن است از برداشتن گام‌های عمدی برای «مسطح کردن» رشته برش‌خورده سود ببرد.

system / Context

اشیاء داخلی از نوع system / Context حاوی متغیرهای محلی از یک بسته می‌باشند - یک محدوده جاوا اسکریپت که یک تابع تودرتو می‌تواند به آن دسترسی داشته باشد.

هر نمونه تابع حاوی یک اشاره گر داخلی به Context است که در آن اجرا می شود تا بتواند به آن متغیرها دسترسی داشته باشد. حتی اگر اشیاء Context مستقیماً از جاوا اسکریپت قابل مشاهده نیستند، شما کنترل مستقیم روی آنها دارید.

(system)

این دسته شامل اشیاء داخلی مختلفی است که (هنوز) به روش معنی‌داری طبقه‌بندی نشده‌اند.

نمای مقایسه

نمای مقایسه به شما امکان می دهد اشیاء لو رفته را با مقایسه چند عکس فوری با یکدیگر پیدا کنید. به عنوان مثال، انجام یک عمل و معکوس کردن آن، مانند باز کردن یک سند و بستن آن، نباید اشیاء اضافی را پشت سر بگذارد.

برای تأیید اینکه یک عملیات خاص نشت ایجاد نمی کند:

  1. قبل از انجام عملیات یک عکس فوری از پشته بگیرید.
  2. یک عملیات انجام دهید. یعنی با صفحه ای به گونه ای تعامل کنید که فکر می کنید ممکن است باعث نشت شود.
  3. یک عملیات معکوس انجام دهید. یعنی برعکس آن را انجام دهید و چند بار تکرار کنید.
  4. یک عکس فوری پشته دوم بگیرید و نمای آن را به مقایسه تغییر دهید و آن را با عکس فوری 1 مقایسه کنید.

نمای مقایسه تفاوت بین دو عکس فوری را نشان می دهد. هنگام گسترش یک ورودی کل، نمونه های شی اضافه شده و حذف شده نشان داده می شوند:

در مقایسه با Snapshot 1.

نمای مهاری

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

نما چندین نقطه ورودی را ارائه می دهد:

  • اشیاء DOMWindow اشیاء جهانی برای کد جاوا اسکریپت.
  • ریشه های GC ریشه های GC که توسط زباله جمع کن ماشین مجازی استفاده می شود. ریشه‌های GC می‌توانند شامل نقشه‌های داخلی، جداول نمادها، پشته‌های رشته ماشین مجازی، حافظه‌های پنهان کامپایل، دامنه‌های دسته و دسته‌های جهانی باشند.
  • اشیاء بومی اشیاء مرورگر به داخل ماشین مجازی جاوا اسکریپت فشار داده می‌شوند تا امکان اتوماسیون را فراهم کنند، برای مثال، گره‌های DOM و قوانین CSS.

نمای مهار

بخش نگهدارنده ها

بخش Retainers در پایین پانل حافظه اشیایی را نشان می دهد که به شی انتخاب شده در نما اشاره می کنند. پانل Memory بخش Retainers را هنگامی که در هر یک از نماها به جز Statistics شیء متفاوتی را انتخاب می کنید، به روز می کند.

بخش نگهدارنده ها

در این مثال، رشته انتخاب شده توسط ویژگی x یک نمونه Item حفظ می شود.

نگهدارنده ها را نادیده بگیرید

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

گزینه 'نادیده گرفتن این نگهدارنده' در منوی کشویی.

برای مخفی کردن یک نگهدارنده، کلیک راست کرده و گزینه Ignore this retainer را انتخاب کنید. نگهدارنده های نادیده گرفته شده به عنوان ignored در ستون Distance علامت گذاری می شوند. برای توقف نادیده گرفتن همه نگهدارنده‌ها، روی بازیابی نگهدارنده‌های نادیده گرفته شده در نوار اقدام در بالا کلیک کنید.

یک شی خاص را پیدا کنید

برای پیدا کردن یک شی در پشته جمع‌آوری‌شده می‌توانید با استفاده از Ctrl + F جستجو کنید و شناسه شی را وارد کنید.

نام توابع برای تشخیص بسته شدن

نامگذاری توابع کمک زیادی می کند تا بتوانید بین بسته شدن ها در عکس فوری تمایز قائل شوید.

به عنوان مثال، کد زیر از توابع نامگذاری شده استفاده نمی کند:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

در حالی که این مثال انجام می دهد:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

تابع نامگذاری شده در یک بسته.

نشت DOM را کشف کنید

Heap profiler این توانایی را دارد که وابستگی های دوطرفه بین اشیاء بومی مرورگر (گره های DOM و قوانین CSS) و اشیاء جاوا اسکریپت را منعکس کند. این به کشف نشتی‌های نامرئی کمک می‌کند که به دلیل زیردرخت‌های DOM جدا شده فراموش شده در اطراف شناور هستند.

نشت DOM می تواند بزرگتر از آن چیزی باشد که فکر می کنید. مثال زیر را در نظر بگیرید. زباله های #tree درخت چه زمانی جمع آوری می شود؟

  var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //#tree can't be GC yet due to treeRef
  treeRef = null;

  //#tree can't be GC yet due to indirect
  //reference from leafRef

  leafRef = null;
  //#NOW #tree can be garbage collected

#leaf یک ارجاع به والد خود ( parentNode ) و به صورت بازگشتی تا #tree حفظ می‌کند، بنابراین تنها زمانی که leafRef باطل شود، کل درخت زیر #tree کاندید GC می‌شود.

زیردرخت های DOM