بهترین شیوه های مدیریت حافظه

این سند فرض می‌کند که شما بهترین دستورالعمل‌ها را برای برنامه‌های Android تحت مدیریت حافظه، مانند مدیریت حافظه برنامه خود، دنبال کرده‌اید.

معرفی

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

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

قبل از تماس با پشتیبانی

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

جلوگیری از نشت حافظه

این بهترین شیوه‌ها را دنبال کنید تا از برخی از رایج‌ترین دلایل نشت حافظه در کدهایی که از Google SDK استفاده می‌کنند جلوگیری کنید.

بهترین روش ها برای برنامه های اندروید

بررسی کنید که تمام کارهای زیر را در برنامه اندروید خود انجام داده اید:

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

برای جزئیات خاص هر یک از این شیوه ها، بخش های زیر را ببینید.

منابع استفاده نشده را آزاد کنید

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

ارجاعات قدیمی GoogleMap را در GeoSDK منتشر کنید

یک اشتباه رایج این است که GoogleMap در صورت ذخیره با استفاده از NavigationView یا MapView می تواند باعث نشت حافظه شود. یک GoogleMap یک رابطه 1 به 1 با NavigationView یا MapView دارد که از آن بازیابی شده است. یا باید اطمینان حاصل کنید که یک GoogleMap در حافظه پنهان ذخیره نمی شود، یا اینکه با فراخوانی NavigationView#onDestroy یا MapView#onDestroy، مرجع منتشر می شود. اگر از NavigationSupportFragment، MapSupportFragment یا قطعه خودتان که این نماها را بسته بندی می کند استفاده می کنید، آنگاه مرجع باید در Fragment#onDestroyView منتشر شود.

class NavFragment : SupportNavigationFragment() {

  var googleMap: GoogleMap?

  override fun onCreateView(
    inflater: LayoutInflater,
    parent: ViewGroup?,
    savedInstanceState: Bundle?,
  ): View  {
    super.onCreateView(inflater,parent,savedInstanceState)
    getMapAsync{map -> googleMap = map}
  }

  override fun onDestroyView() {
    googleMap = null
  }
}

وقتی دیگر مورد نیاز نیست، شنوندگان را لغو ثبت کنید

هنگامی که برنامه Android شما شنونده ای را برای رویدادی ثبت می کند، مانند کلیک کردن بر روی دکمه یا تغییر در وضعیت یک نما، زمانی که برنامه دیگر نیازی به نظارت بر رویداد ندارد، حتماً شنونده را لغو ثبت کنید. اگر این کار را نکنید، شنوندگان حتی پس از اتمام برنامه شما با آنها به حافظه خود ادامه می دهند.

برای مثال، فرض کنید برنامه شما از Navigation SDK استفاده می کند و شنونده زیر را برای گوش دادن به رویدادهای ورود فرا می خواند: روش addArrivalListener برای گوش دادن به رویدادهای ورود، همچنین باید removeArrivalListener زمانی که دیگر نیازی به نظارت بر رویدادهای ورود ندارد فراخوانی کند.

var arrivalListener: Navigator.ArrivalListener? = null

fun registerNavigationListeners() {
  arrivalListener =
    Navigator.ArrivalListener {
      ...
    }
  navigator.addArrivalListener(arrivalListener)
}

override fun onDestroy() {
  navView.onDestroy()
  if (arrivalListener != null) {
    navigator.removeArrivalListener(arrivalListener)
  }

  ...
  super.onDestroy()
}

در صورت عدم نیاز، وظایف را لغو کنید

هنگامی که یک برنامه Android یک کار ناهمزمان را شروع می کند، مانند دانلود یا درخواست شبکه، مطمئن شوید که کار را پس از اتمام آن لغو کرده اید. اگر کار لغو نشود، حتی پس از اتمام برنامه با آن، در پس‌زمینه به کار خود ادامه می‌دهد.

برای جزئیات بیشتر در مورد بهترین شیوه ها، به مدیریت حافظه برنامه خود در اسناد Android مراجعه کنید.

روش‌های چرخه عمر رو به جلو برای آزادسازی منابع

اگر برنامه شما از Navigation یا Maps SDK استفاده می‌کند، مطمئن شوید که منابع را با باز ارسال روش‌های چرخه حیات (به صورت پررنگ نشان داده شده است) به navView آزاد کنید. می توانید این کار را با استفاده از NavigationView در Navigation SDK یا MapView در Maps یا Navigation SDK انجام دهید. همچنین می‌توانید از SupportNavigationFragment یا SupportMapFragment به‌جای استفاده مستقیم از NavigationView و MapView استفاده کنید. قطعات پشتیبانی حمل و نقل روش های چرخه حیات را کنترل می کنند.

class NavViewActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    navView = ...
    navView.onCreate(savedInstanceState)
    ...
  }

  override fun onSaveInstanceState(savedInstanceState: Bundle) {
    super.onSaveInstanceState(savedInstanceState)
    navView.onSaveInstanceState(savedInstanceState)
  }

  override fun onTrimMemory(level: Int) {
    super.onTrimMemory(level)
    navView.onTrimMemory(level)
  }

  /* Same with
    override fun onStart()
    override fun onResume()
    override fun onPause()
    override fun onConfigurationChanged(...)
    override fun onStop()
    override fun onDestroy()
  */
}

از آخرین نسخه های SDK استفاده کنید

Google SDK به طور مداوم با ویژگی های جدید، رفع اشکالات و بهبود عملکرد به روز می شود. برای دریافت این اصلاحات، SDK های موجود در برنامه خود را به روز نگه دارید.

اشکال زدایی نشت حافظه

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

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

برای رفع اشکال نشت حافظه، این فرآیند را دنبال کنید:

  1. موضوع را دوباره ایجاد کنید . این مرحله برای رفع اشکال آن ضروری است.
  2. بررسی کنید که آیا استفاده از حافظه مورد انتظار است یا خیر . بررسی کنید افزایش مصرفی که به نظر می رسد نشت است، در واقع حافظه مورد نیاز برای اجرای برنامه شما نباشد.
  3. اشکال زدایی در سطح بالا . چندین ابزار وجود دارد که می توانید از آنها برای رفع اشکال استفاده کنید. سه مجموعه ابزار استاندارد مختلف به رفع اشکال حافظه در اندروید کمک می کند: Android Studio، Perfetto، و ابزارهای خط فرمان Android Debug Bridge (adb).
  4. میزان استفاده از حافظه برنامه خود را بررسی کنید . یک heap dump و ردیابی تخصیص دریافت کنید و سپس آن را تجزیه و تحلیل کنید.
  5. رفع نشت حافظه

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

مرحله 1: مشکل را دوباره ایجاد کنید

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

  • چه مجموعه ای از ویژگی ها فعال می شوند؟

  • چه توالی خاصی از اقدامات کاربر باعث نشت می شود؟

    • آیا چندین تکرار برای فعال کردن این دنباله امتحان کرده اید؟
  • برنامه از کدام ایالت های چرخه حیات عبور کرده است؟

    • آیا چندین تکرار را از طریق حالت های مختلف چرخه زندگی امتحان کرده اید؟

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

مرحله 2: بررسی کنید که آیا استفاده از حافظه برای برنامه مورد انتظار است یا خیر

هر ویژگی به حافظه اضافی نیاز دارد. هنگامی که سناریوهای مختلف را اشکال زدایی می کنید، در نظر بگیرید که آیا می توان از این مورد انتظار استفاده کرد یا اینکه در واقع نشت حافظه است. به عنوان مثال، برای ویژگی های مختلف یا وظایف کاربر، احتمالات زیر را در نظر بگیرید:

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

  • استفاده احتمالی از حافظه مورد انتظار : پس از توقف سناریو، حافظه بازیابی می شود.

  • استفاده احتمالی مورد انتظار حافظه : استفاده از حافظه برای مدتی افزایش می‌یابد و سپس کاهش می‌یابد. این می تواند به دلیل حافظه نهان محدود یا دیگر استفاده از حافظه مورد انتظار باشد.

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

مرحله 3: اشکال زدایی در سطح بالا

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

نمایه کننده حافظه اندروید استودیو

این ابزار هیستوگرام بصری حافظه مصرف شده را در اختیار شما قرار می دهد. Heap dump و ردیابی تخصیص نیز می تواند از همین رابط فعال شود. این ابزار توصیه پیش فرض است. برای اطلاعات بیشتر، نمایه حافظه اندروید استودیو را ببینید.

شمارشگر حافظه Perfetto

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

Perfetto user interface

ابزارهای خط فرمان پل اشکال زدایی اندروید (adb).

بسیاری از مواردی که می توانید با Perfetto ردیابی کنید به عنوان یک ابزار خط فرمان adb نیز موجود است که می توانید مستقیماً آن را جستجو کنید. چند مثال مهم عبارتند از:

  • Meminfo به شما امکان می دهد اطلاعات دقیق حافظه را در یک نقطه از زمان مشاهده کنید.

  • Procstats برخی از آمارهای انباشته مهم را در طول زمان ارائه می دهد.

یک آمار مهم که در اینجا باید به آن نگاه کرد، حداکثر ردپای حافظه فیزیکی (maxRSS) است که برنامه در طول زمان به آن نیاز دارد. MaxPSS ممکن است دقیق نباشد. برای راهی برای افزایش دقت، پرچم adb shell dumpsys procstats --help –start-testing را ببینید.

ردیابی تخصیص

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

مرحله 4: میزان استفاده از حافظه برنامه خود را با یک Heap Dump بررسی کنید

یکی از راه‌های تشخیص نشت حافظه این است که از برنامه خود یک پشته خالی بگیرید و سپس آن را برای نشت بررسی کنید. Heap Dump یک عکس فوری از تمام اشیاء در حافظه یک برنامه است. می توان از آن برای تشخیص نشت حافظه و سایر مشکلات مربوط به حافظه استفاده کرد.

Android Studio می تواند نشت حافظه را که توسط GC قابل رفع نیست، تشخیص دهد. هنگامی که یک heap dump را می گیرید، Android Studio بررسی می کند که آیا فعالیت یا قطعه ای وجود دارد که هنوز قابل دسترسی است اما قبلاً از بین رفته است.

  1. یک توده زباله را ضبط کنید .
  2. برای یافتن نشت حافظه، حفره پشته را تجزیه و تحلیل کنید .
  3. رفع نشت حافظه

برای جزئیات، بخش های زیر را ببینید.

یک توده زباله را ضبط کنید

برای ثبت یک پشته، می‌توانید از پل اشکال‌زدایی Android (adb) یا نمایه‌ساز حافظه Android Studio استفاده کنید.

از adb برای گرفتن heap dump استفاده کنید

برای گرفتن heap dump با استفاده از adb ، این مراحل را دنبال کنید:

  1. دستگاه اندروید خود را به رایانه وصل کنید.
  2. یک خط فرمان باز کنید و به دایرکتوری که ابزارهای adb در آن قرار دارند بروید.
  3. برای گرفتن یک heap dump، این دستور را اجرا کنید:

    adb shell am dumpheap my.app.name $PHONE_FILE_OUT

  4. برای بازیابی heap dump، این دستور را اجرا کنید:

    adb pull $PHONE_FILE_OUT $LOCAL_FILE.

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

برای گرفتن یک heap dump با استفاده از نمایه‌ساز حافظه Android Studio، این مراحل را در بخش Android Capture a Heapdump دنبال کنید.

برای یافتن نشت حافظه، حفره پشته را تجزیه و تحلیل کنید

هنگامی که یک heap dump را ضبط کردید، می توانید از نمایه حافظه Android Studio برای تجزیه و تحلیل آن استفاده کنید. برای انجام این کار؛ این موارد را دنبال کنید:

  1. پروژه اندروید خود را در اندروید استودیو باز کنید.

  2. Run را انتخاب کنید و سپس پیکربندی Debug را انتخاب کنید.

  3. تب Android Profiler را باز کنید.

  4. حافظه را انتخاب کنید.

  5. Open heap dump را انتخاب کنید و فایل heap dump را که ایجاد کرده اید انتخاب کنید. نمایه ساز حافظه نموداری از میزان استفاده از حافظه برنامه شما را نشان می دهد.

  6. از نمودار برای تجزیه و تحلیل heap dump استفاده کنید:

    • اشیایی که دیگر استفاده نمی شوند را شناسایی کنید.

    • اشیایی که از حافظه زیادی استفاده می کنند را شناسایی کنید.

    • ببینید هر شی چقدر از حافظه استفاده می کند.

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

مرحله 5: رفع نشت حافظه

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

سایر ابزارهای رفع اشکال

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

اشکال زدایی حافظه در کد بومی با ردیابی تخصیص

حتی اگر مستقیماً از کد بومی استفاده نمی کنید، چندین کتابخانه رایج اندروید از جمله Google SDK از آن استفاده می کنند. اگر فکر می کنید نشت حافظه شما در کد بومی است، چندین ابزار وجود دارد که می توانید برای رفع اشکال آن استفاده کنید. ردیابی تخصیص با Android Studio یا heapprofd (همچنین با Perfetto سازگار است) یک راه عالی برای شناسایی دلایل احتمالی نشت حافظه است و اغلب سریع‌ترین راه برای رفع اشکال است.

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

نشتی ها را با LeakCanary شناسایی کنید

LeakCanary یک ابزار قدرتمند برای شناسایی نشت حافظه در برنامه های اندروید است. برای کسب اطلاعات بیشتر در مورد نحوه استفاده از LeakCanary در برنامه خود، از LeakCanary دیدن کنید.

نحوه گزارش مشکلات مربوط به Google SDK

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

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

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

  • اگر انتظار نشت حافظه بومی وجود دارد ، خروجی ردیابی تخصیص را از heapprofd به اشتراک بگذارید.

  • گزارش اشکالی که پس از ایجاد مجدد وضعیت نشتی گرفته شده است.

  • ردی از هرگونه خرابی مربوط به حافظه را پشته کنید .

    نکته مهم : ردیابی پشته معمولاً به تنهایی برای رفع اشکال یک مشکل حافظه کافی نیست، بنابراین مطمئن شوید که یکی از اشکال دیگر اطلاعات را نیز ارائه می دهید.