درباره مدیریت حافظه

بهینه‌سازی حافظه برای ارائه تجربه‌های بازی پایدار و با عملکرد بالا در Android بسیار مهم است. این راهنما نمای کلی‌ای از اینکه چرا کارایی حافظه مهم است، چگونه سیستم‌عامل Android محدودیت‌های حافظه پردازش را مدیریت می‌کند، و سنجه‌های جدید حافظه در «کنسول Google Play» برای کمک به شما در نظارت و بهبود کیفیت فنی بازی‌تان ارائه می‌دهد.

اهمیت بهینه‌سازی حافظه

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

  • جلوگیری از شروع سرد (تجربه کاربری و حفظ کاربر): وقتی بازیکن به‌طور موقت از بازی شما خارج می‌شود (برای مثال، برای پاسخ دادن به اعلان یا بررسی پیام)، سیستم‌عامل فرایند بازی را در پس‌زمینه قرار می‌دهد. اگر ردپای حافظه پس‌زمینه بازی خیلی زیاد باشد، «بستن ناشی از کمبود حافظه» (LMK) سیستم برای بازپس‌گیری حافظه دسترسی تصادفی برای کارهای پیش‌زمینه، خاتمه دادن به فرایند بازی را در اولویت قرار می‌دهد. دفعه بعد که کاربر بازی را ازسر می‌گیرد، به‌جای ازسرگیری گرم یکپارچه و آنی، بازی باید شروع سرد طولانی را طی کند و دارایی‌های گرافیکی سنگین، صدا، و فایل‌های دودویی موتور بازی را به‌طور کامل از فضای ذخیره‌سازی بارگیری مجدد کند. پایین نگه داشتن میزان استفاده از حافظه پس‌زمینه از این توقف‌های بی‌صدای پس‌زمینه جلوگیری می‌کند، وضعیت کاربر را حفظ می‌کند، و تضمین می‌کند که بازیکنان می‌توانند فوراً جلسه خود را ازسر بگیرند. برای جزئیات بیشتر درباره رفتار «بستن ناشی از کمبود حافظه» سیستم، به راهنمای معیارهای کلیدی Android - بستن ناشی از کمبود حافظه مراجعه کنید.
  • پایداری بوم‌سازگان و دستگاه: استفاده ناکارآمد از حافظه و نشت حافظه باعث کاهش سلامت کلی سیستم می‌شود. وقتی حافظه سیستم کم باشد، سیستم با فشار شدیدی مواجه می‌شود که منجر به افت نرخ فریم، لکنت رابط کاربری، و اشکالات صوتی می‌شود. اگر فشار حافظه خیلی شدید باشد، «بستن ناشی از کمبود حافظه» (LMK) سیستم به‌طور تهاجمی فرایندهای پس‌زمینه را خاتمه می‌دهد و باعث می‌شود وقتی بازیکنان بین تکالیف جابه‌جا می‌شوند، سایر برنامه‌ها شروع سرد آهسته و ازدست رفتن وضعیت کاربر را تجربه کنند.
  • خاتمه دادن در سطح پلاتفرم: از Android 17 (سطح میانای برنامه‌سازی کاربردی ۳۷)، سیستم به‌طور فعال‌تری فرایندهایی را که بیش‌ازحد از حافظه استفاده می‌کنند خاتمه می‌دهد. اگر ردپای بازی شما بیش‌ازحد زیاد باشد، سیستم‌عامل می‌تواند فرایند آن را به‌طور ناگهانی و بدون تولید ردیابی پشته استاندارد خاتمه دهد.
  • سازگاری دستگاه: درحالی‌که دستگاه‌های پرچم‌دار دارای ۱۲ تا ۱۶ گیگابایت حافظه دسترسی تصادفی هستند، بخش عظیمی از مخاطبان جهانی بازی از دستگاه‌هایی با ۴ یا ۶ گیگابایت حافظه دسترسی تصادفی استفاده می‌کنند. مدیریت صحیح حافظه تضمین می‌کند که بازی شما در همه سطوح سخت‌افزاری بدون نیاز به بسته‌های دارایی پیچیده و جداگانه، دردسترس و پاسخگو باقی بماند.

آشنایی با حافظه در Android

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

مفاهیم اصلی حافظه Android

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

  • نمای کلی حافظه: Android از صفحه‌بندی و نگاشت حافظه (mmap) برای مدیریت RAM استفاده می‌کند. این سیستم‌عامل از فایل مبادله سنتی روی دیسک پشتیبانی نمی‌کند؛ درعوض، برای آزاد کردن حافظه فیزیکی، به فشرده‌سازی صفحه (بااستفاده از zRAM) و بازیابی صفحه متکی است.
  • تخصیص حافظه بین پردازش‌ها: Android حافظه دسترسی تصادفی را در سراسر سیستم هم‌رسانی می‌کند. این سیستم‌عامل پشته‌های خاصی را برای اجرای ماشین مجازی Dalvik یا ART اختصاص می‌دهد، درحالی‌که به محیط‌های توسعه بومی (مانند موتورهای بازی C++) اجازه می‌دهد تا از پشته سیستم بومی درخواست حافظه کنند.
  • مدیریت حافظه برنامه: Android که تحت مدل چندفرایندی کار می‌کند، از برنامه‌ها انتظار دارد وضعیت چرخه حیات خود را به‌طور پویا نظارت کنند و منابع غیرضروری (مانند گرافیک‌های ذخیره‌نشده در حافظه نهان و نقشه‌های بیتی) را داوطلبانه آزاد کنند تا از سلامت سیستم پشتیبانی شود.
  • نمای کلی فرایندها و رشته‌ها: سیستم فرایندها را براساس اهمیت و نمایان بودن فعلی آن‌ها از دید کاربر در سلسله‌مراتبی دسته‌بندی می‌کند و تعیین می‌کند که کدام فرایندها زنده نگه داشته شوند و کدام فرایندها در شرایط کمبود حافظه زودتر خاتمه یابند.

سنجه ردپای حافظه کل

«محدودکننده حافظه» Android 17 در سطح پلاتفرم، مصرف فرایند را بااستفاده از «ردپای حافظه کل» ارزیابی می‌کند، نه اندازه کل مقیم (RSS) یا اندازه حافظه مجازی.

ردپای حافظه کل = RSS ناشناس (RssAnon) + فضای مبادله فشرده‌نشده (VmSwap)

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

محدودیت‌های حافظه

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

محدودکننده حافظه در Android 17 و بالاتر

Android 17 (سطح API‏ ۳۷) و بالاتر، محدودیت‌های حافظه سخت‌گیرانه و مختص هر برنامه را بااستفاده از Linux cgroup v2 مدیریت می‌کنند تا از ایجاد ناپایداری در سراسر سیستم توسط برنامه‌های مجزا جلوگیری کنند. برای جزئیات بیشتر درباره پیاده‌سازی فنی، به راهنمای محدودکننده حافظه AOSP و اولویت‌بندی کارایی حافظه: مراحل ضروری برای وبلاگ Android 17 مراجعه کنید.

  • سازوکار: «محدودکننده حافظه» همه فرایندهای برنامه را پایش می‌کند و براساس وضعیت چرخه حیات فرایند، محدودیت‌ها را به‌طور پویا اختصاص می‌دهد:
    • فرایندهای نمایان (پیش‌زمینه): انتظار می‌رود فرایندهای برنامه‌ای که درحال‌حاضر واسط کاربری را نمایش می‌دهند، مجموعه کاری منابع بزرگ‌تری را اجرا کنند و حد سخاوتمندانه‌تری به آن‌ها اختصاص داده می‌شود.
    • فرایندهای غیرقابل‌مشاهده (پس‌زمینه یا سرویس‌ها): فرایندهای برنامه که کار فعالی را بدون نمایش واسط کاربری انجام می‌دهند به بودجه محدودتر و سخت‌گیرانه‌تری محدود می‌شوند.
  • مشخصه‌های هسته: این سرویس به دو مشخصه اصلی متکی است:
    • memory.high: حد نرم. وقتی از این حد فراتر رود، هسته پردازش را محدود می‌کند و تلاش می‌کند حافظه را به‌طور تهاجمی پس بگیرد. این بازیابی می‌تواند باعث شود عملکرد بازی افت کند.
    • memory.swap.max: حد نهایی فضای swap یا zRAM را که فرایند می‌تواند استفاده کند مدیریت می‌کند.
  • رفتار فسخ: اگر فرایندی به اختصاص دادن حافظه ناشناس پس‌از memory.high ادامه دهد و ظرفیت مبادله آن تمام شود، اختصاص دادن‌ها ناموفق می‌شود، و سیستم‌عامل فرایند را بدون اطلاع کاربر متوقف می‌کند. این توقف بااستفاده از ApplicationExitInfo تحت دلیل خروج محدودکننده حافظه ثبت می‌شود (از Android 17،‏ 26Q4 دردسترس است).

محدودیت‌های جدید حافظه در «معیارهای کلیدی کنسول Play»

برای کمک به توسعه‌دهندگان در شناسایی پیشگیرانه مشکلات حافظه، Google Play سنجه‌های جدیدی را در «معیارهای کلیدی Android» در «کنسول Play» معرفی می‌کند. «کنسول Play» صدک ۹۰ (P90) ردپای حافظه RSS ناشناس + Swap جلسه‌های بازی شما را ردیابی می‌کند تا موارد پرت شدید را شناسایی کند.

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

برای دستورالعمل‌های دقیق و محدودیت‌های حافظه، به معیارهای کلیدی Android - «آستانه‌های رفتار بد چیست؟» مراجعه کنید.

سرویس‌های محسوس برای کاربر

«سرویس‌های قابل‌درک» فرایندهای پس‌زمینه مهمی هستند که سیستم Android آن‌ها را برای کاربر قابل‌توجه می‌داند. این وضعیت شامل همه فرایندهای درحال اجرا می‌شود:

  • سرویس‌های پیش‌زمینه‌ای (FGS)
  • کارهای تسریع‌شده
  • کارهای انتقال داده آغازشده ازسوی کاربر
  • سرویس‌های محدود به سیستم یا سرویس‌های محدودشده توسط برنامه‌های دیگر

ازآنجایی‌که «سرویس‌های قابل‌درک» برای کارهای مهم و طولانی‌مدت در پس‌زمینه طراحی شده‌اند، به‌شدت دربرابر نشت‌های تجمعی چرخه حیات آسیب‌پذیر هستند. محدودیت‌های حافظه پلاتفرم Android این وضعیت را به‌عنوان «پیش‌زمینه» درنظر نمی‌گیرد، یعنی اگر بازی شما در پس‌زمینه باشد اما همچنان «سرویس قابل‌تشخیص» را اجرا کند، مشمول محدودیت‌های سخت‌گیرانه‌تر حافظه پس‌زمینه یا سرویس نشان‌داده‌شده در صفحه «مرکز راهنمایی Play» می‌شود. بازی‌ها باید هنگام انتقال از پیش‌زمینه به وضعیت «سرویس قابل‌تشخیص» پس‌زمینه، دارایی‌های غیرضروری را به‌طور تهاجمی حذف کنند.

الزامات R8

برای به‌حداقل رساندن اندازه بایت‌کد و کاهش سربار فرایند Java پایه، «کنسول Google Play» بهینه‌سازی کد را به‌عنوان بخشی از دستورالعمل‌های کیفیت برنامه ارزیابی می‌کند. برای اطلاعات بیشتر درباره الزامات و محدودیت‌های بهینه‌سازی که برای بازی‌ها اعمال می‌شود، به بهینه‌سازی کد DEX در اسناد معیارهای کلیدی Android مراجعه کنید.

برای پیکربندی R8 در پروژه استاندارد Android، راهنمای فعال کردن بهینه‌سازی برنامه را دنبال کنید. برای فعال کردن تنظیمات بهینه‌سازی و کوچک‌سازی پیشرفته، استفاده از R8 در حالت کامل را ببینید. برای شناسایی قوانینی که مانع از مبهم‌سازی کلاس‌ها یا حذف کد مرده توسط R8 می‌شوند، از R8 Configuration Analyzer استفاده کنید.

اگر با موتور بازی می‌سازید، رفتار پیش‌فرض R8 بسته به موتور و نسخه متفاوت است:

  • Unity: کوچک‌سازی کد به‌طور پیش‌فرض غیرفعال است، بنابراین باید آن را در تنظیمات پروژه‌تان فعال کنید. برای کسب اطلاعات بیشتر درباره پشتیبانی نسخه و مراحل پیکربندی، به کوچک کردن و بهینه‌سازی کد Unity با R8 مراجعه کنید.
  • Unreal Engine: از UE 4.25 به بعد، R8 به‌طور پیش‌فرض در ساخت‌های «نسخه پخش» فعال است و لازم است قوانین نگهداری را برای افزایه‌ها و پل‌های JNI مدیریت کنید. برای کسب اطلاعات بیشتر درباره جزئیات نسخه و پیکربندی UPL، به کوچک کردن و بهینه‌سازی کد Unreal Engine با R8 مراجعه کنید.

الزامات بیت‌مپ

بیت‌مپ‌ها بخش عظیمی از استفاده از حافظه را در بازی‌های مدرن با کیفیت بالا تشکیل می‌دهند. ازآنجایی‌که داده‌های پیکسل Bitmap مستقیماً در توده بومی مدیریت‌نشده در Android نسخه ۸.۰ (سطح API‏ ۲۶) و بالاتر ذخیره می‌شود، بار کردن تصویر بهینه‌نشده می‌تواند فرایندها را از آستانه حافظه پلاتفرم فراتر ببرد. برای روال‌های مطلوب در مقیاس‌بندی و ذخیره موقت تصویر، به بهینه‌سازی استفاده از تصویر مراجعه کنید.

پایش استفاده از حافظه

برای بهینه‌سازی مؤثر حافظه بازی‌تان، ابتدا باید بدانید پلاتفرم Android چگونه ردپای آن را اندازه‌گیری می‌کند. Android 17 سنجه حافظه را به‌روز می‌کند تا مجموع RSS ناشناس (RssAnon) و Swap غیرفشرده (VmSwap) را ردیابی کند، به‌استثنای حافظه با پشتیبانی فایل یا حافظه خصوصی GPU. این راهنما جزئیات نحوه استفاده از ابزارهای سطح سیستم مانند Perfetto و meminfo، پیاده‌سازی میاناهای برنامه‌سازی کاربردی عیب‌یابی مانند ProfilingManager و onTrimMemory، و استخراج تخصیص‌های دقیق حافظه در Unity و Unreal Engine را شرح می‌دهد. با نحوه نمایه کردن دقیق بازی‌تان و اجتناب از لکنت‌های عملکردی مرتبط با نظرسنجی سنتی حافظه زمان اجرا آشنا شوید.

برای اطلاعات بیشتر، پایش استفاده از حافظه را ببینید.

راهبردهای کاهش حافظه

اگرچه موتورهای بازی توسعه چندسکویی را ساده می‌کنند، مدیریت حافظه پیش‌فرض آن‌ها می‌تواند محدودیت‌های حافظه در سطح سیستم‌عامل را فعال کند. این صفحه مراحل بهینه‌سازی عملی را که به‌طور خاص برای Unity و Unreal Engine طراحی شده‌اند، به‌طور دقیق شرح می‌دهد. ببینید چرا تکیه بر onTrimMemory مبتنی بر Java می‌تواند باعث بن‌بست در Unity شود—و چگونه به‌جای آن از فراخوانی‌های برگشتی چرخه حیات بومی استفاده کنید. همچنین با بهینه‌سازی‌های کلیدی در سطح دارایی آشنا خواهید شد، مانند استفاده از فشرده‌سازی بافت ASTC 8x8 و پیکربندی تخلیه دارایی، تا بازی شما به‌طور روان در همه سطوح سخت‌افزاری اجرا شود.

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