تحلیل و بهینه سازی راه اندازی اپلیکیشن

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

ما استفاده از کتابخانه Macrobenchmark را برای اندازه‌گیری زمان راه‌اندازی توصیه می‌کنیم. این کتابخانه یک مرور کلی و ردیابی‌های دقیق سیستم را ارائه می‌دهد تا دقیقاً ببینید در طول راه‌اندازی چه اتفاقی می‌افتد.

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

برای تجزیه و تحلیل شروع برنامه خود، موارد زیر را انجام دهید:

مراحل تجزیه و تحلیل و بهینه سازی استارتاپ

برنامه‌ها اغلب نیاز دارند منابع خاصی را در طول راه‌اندازی بارگذاری کنند که برای کاربران نهایی حیاتی هستند. منابع غیرضروری می‌توانند تا پس از اتمام راه‌اندازی منتظر بارگذاری بمانند.

برای ایجاد تعادل در عملکرد، موارد زیر را در نظر بگیرید:

  • از کتابخانه Macrobenchmark برای اندازه‌گیری زمان صرف شده برای هر عملیات استفاده کنید و بلوک‌هایی را که تکمیل آنها زمان زیادی می‌برد، شناسایی کنید.

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

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

  • در صورت امکان، عملیات طولانی مدت را به پس‌زمینه منتقل کنید. فرآیندهای پس‌زمینه هنوز هم می‌توانند در هنگام راه‌اندازی بر مصرف CPU تأثیر بگذارند.

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

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

اندازه‌گیری و تحلیل زمان صرف‌شده در عملیات اصلی

وقتی ردیابی کامل راه‌اندازی برنامه را دارید، به ردیابی نگاه کنید و زمان صرف شده برای عملیات اصلی مانند bindApplication یا activityStart را اندازه‌گیری کنید. توصیه می‌کنیم برای تجزیه و تحلیل این ردیابی‌ها از Perfetto یا Android Studio Profilers استفاده کنید.

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

  • بازه‌های زمانی بزرگی را اشغال می‌کنند و می‌توان آنها را بهینه کرد. هر میلی‌ثانیه در عملکرد اهمیت دارد. برای مثال، به دنبال زمان‌های ترسیم Choreographer ، زمان‌های ترکیب اولیه، زمان‌های بارگذاری کتابخانه، تراکنش‌های Binder یا زمان‌های بارگذاری منابع باشید. برای شروع کلی، به تمام عملیاتی که بیش از 20 میلی‌ثانیه طول می‌کشند، نگاه کنید.
  • مسدود کردن رشته اصلی. برای اطلاعات بیشتر، به گزارش پیمایش در Systrace مراجعه کنید.
  • لازم نیست هنگام راه‌اندازی اجرا شود.
  • می‌توانید تا بعد از ترسیم اولین فریم خود صبر کنید.

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

شناسایی عملیات پرهزینه در نخ اصلی

بهترین روش این است که عملیات پرهزینه مانند ورودی/خروجی فایل و دسترسی به شبکه را از نخ اصلی دور نگه دارید. این موضوع در هنگام راه‌اندازی برنامه نیز به همان اندازه مهم است، زیرا عملیات پرهزینه در نخ اصلی می‌تواند برنامه را بی‌پاسخ بگذارد و سایر عملیات حیاتی را به تأخیر بیندازد. StrictMode.ThreadPolicy می‌تواند به شناسایی مواردی که عملیات پرهزینه در نخ اصلی اتفاق می‌افتند کمک کند. فعال کردن StrictMode در نسخه‌های اشکال‌زدایی برای شناسایی مشکلات در اسرع وقت، همانطور که در مثال زیر نشان داده شده است، روش خوبی است:

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        ...
        if (BuildConfig.DEBUG)
            StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder()
                    .detectAll()
                    .penaltyDeath()
                    .build()
            )
        ...
    }
}

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

TTID و TTFD

برای مشاهده مدت زمانی که طول می‌کشد تا برنامه اولین فریم خود را تولید کند، زمان نمایش اولیه (TTID) را اندازه‌گیری کنید. با این حال، این معیار لزوماً زمان لازم برای شروع تعامل کاربر با برنامه شما را نشان نمی‌دهد. معیار زمان نمایش کامل (TTFD) در اندازه‌گیری و بهینه‌سازی مسیرهای کد لازم برای داشتن یک حالت کاملاً قابل استفاده از برنامه مفیدتر است.

برای استراتژی‌های گزارش‌گیری زمانی که رابط کاربری برنامه به طور کامل ترسیم شده است، به بهبود دقت زمان‌بندی راه‌اندازی مراجعه کنید.

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

وضعیت کلی نخ را تجزیه و تحلیل کنید

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

ابزارهایی مانند Android Studio Profiler و Perfetto نمای کلی دقیقی از نخ اصلی و میزان زمان صرف شده در هر مرحله ارائه می‌دهند. برای اطلاعات بیشتر در مورد تجسم ردپاهای Perfetto، به مستندات Perfetto UI مراجعه کنید.

بخش‌های اصلی حالت خواب نخ اصلی را شناسایی کنید

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

کاهش مسدود شدن نخ اصلی و حالت خواب بدون وقفه

به دنبال هر نمونه از مسدود شدن نخ اصلی باشید. Perfetto و Studio Profiler این را با یک نشانگر نارنجی در جدول زمانی وضعیت نخ نشان می‌دهند. عملیات را شناسایی کنید، بررسی کنید که آیا این موارد مورد انتظار هستند یا می‌توان از آنها اجتناب کرد و در صورت لزوم بهینه‌سازی کنید.

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

بهبود زمان راه‌اندازی

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

  • برای افزایش سرعت TTID، محتوا را به صورت تنبل و غیرهمزمان بارگذاری کنید.
  • توابع فراخوانی که فراخوانی‌های binder انجام می‌دهند را به حداقل برسانید. اگر اجتناب‌ناپذیر هستند، مطمئن شوید که با ذخیره مقادیر به جای تکرار فراخوانی‌ها یا انتقال کارهای غیر مسدودکننده به نخ‌های پس‌زمینه، آن فراخوانی‌ها را بهینه می‌کنید.
  • برای اینکه شروع برنامه شما سریع‌تر ظاهر شود، می‌توانید چیزی را که به حداقل رندر نیاز دارد، در اسرع وقت به کاربر نمایش دهید تا بارگذاری بقیه صفحه به پایان برسد.
  • یک پروفایل راه‌اندازی (استارت‌آپ ) ایجاد و به برنامه خود اضافه کنید.
  • از کتابخانه Jetpack App Startup برای ساده‌سازی مقداردهی اولیه کامپوننت‌ها در هنگام راه‌اندازی برنامه استفاده کنید.

تحلیل عملکرد رابط کاربری

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

محدود کردن کار روی مقداردهی اولیه

ممکن است بارگذاری برخی فریم‌ها نسبت به بقیه زمان بیشتری ببرد. این موارد، هزینه‌های گزافی برای برنامه محسوب می‌شوند.

برای بهینه سازی مقداردهی اولیه، موارد زیر را انجام دهید:

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

داده‌های فریم اندازه‌گیری

روش‌های متعددی برای اندازه‌گیری داده‌های چارچوب وجود دارد. پنج روش اصلی جمع‌آوری به شرح زیر است:

  • جمع‌آوری محلی با استفاده از dumpsys gfxinfo : همه فریم‌های مشاهده شده در داده‌های dumpsys مسئول رندر کند برنامه شما نیستند یا تأثیری بر کاربران نهایی ندارند. با این حال، این معیار خوبی برای بررسی در چرخه‌های انتشار مختلف است تا روند کلی عملکرد را درک کنید. برای کسب اطلاعات بیشتر در مورد استفاده از gfxinfo و framestats برای ادغام اندازه‌گیری‌های عملکرد رابط کاربری در شیوه‌های تست خود، به اصول تست برنامه‌های اندروید مراجعه کنید.
  • جمع‌آوری فیلد با استفاده از JankStats : زمان رندر فریم را از قسمت‌های خاصی از برنامه خود با کتابخانه JankStats جمع‌آوری کرده و داده‌ها را ثبت و تجزیه و تحلیل کنید.
  • در آزمایش‌هایی که با استفاده از Macrobenchmark (Perfetto under the hood) انجام شد
  • Perfetto FrameTimeline : در اندروید ۱۲ (سطح API ۳۱) یا بالاتر، می‌توانید معیارهای جدول زمانی Frame را از یک مسیر Perfetto جمع‌آوری کنید تا مشخص کنید کدام کار باعث افت فریم می‌شود. این می‌تواند اولین قدم برای تشخیص دلیل افت فریم باشد.
  • پروفایلر اندروید استودیو برای تشخیص هرزنامه

زمان بارگذاری فعالیت اصلی را بررسی کنید

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

  • reportFullyDrawn برای گزارش به سیستم مبنی بر اینکه برنامه شما اکنون برای اهداف بهینه‌سازی به طور کامل ترسیم شده است، استفاده کنید.
  • اندازه‌گیری فعالیت و راه‌اندازی برنامه‌ها با استفاده از StartupTimingMetric و کتابخانه Macrobenchmark.
  • به افت فریم نگاه کنید.
  • طرح‌بندی‌هایی را که رندر یا اندازه‌گیری آنها زمان زیادی می‌برد، شناسایی کنید.
  • شناسایی دارایی‌هایی که بارگذاری آنها مدت زیادی طول می‌کشد.
  • عناصر رابط کاربری غیرضروری که در ترکیب اولیه گنجانده شده‌اند را شناسایی کنید.

این راه‌حل‌های ممکن را برای بهینه‌سازی زمان بارگذاری فعالیت اصلی در نظر بگیرید:

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

    var shouldLoad by remember {mutableStateOf(false)}
    
    if (shouldLoad) {
     MyComposable()
    }
    

    با تغییر shouldLoad کامپوننت‌ها را درون بلوک شرطی بارگذاری کنید:

    LaunchedEffect(Unit) {
     shouldLoad = true
    }
    

    این باعث ایجاد یک ترکیب مجدد می‌شود که شامل کد داخل بلوک شرطی در قطعه کد اول می‌شود.

    برای اطلاعات بیشتر در مورد بهینه‌سازی عملکرد Compose، به بهترین شیوه‌ها مراجعه کنید.

{% کلمه به کلمه %} {% فعل کمکی %} {% کلمه به کلمه%} {% فعل کمکی %}