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

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

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

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

برای تجزیه‌وتحلیل راه‌اندازی برنامه‌تان، کارهای زیر را انجام دهید:

مراحل تحلیل و بهینه‌سازی راه‌اندازی

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

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

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

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

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

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

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

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

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

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

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

  • بازه زمانی زیادی را اشغال می‌کنند و می‌توانند بهینه‌سازی شوند. هر میلی‌ثانیه در عملکرد مهم است. برای مثال، به‌دنبال Choreographer زمان‌های ترسیم، زمان‌های ترکیب‌بندی اولیه، زمان‌های بار کردن کتابخانه، Binder تراکنش‌ها، یا زمان‌های بار کردن منبع بگردید. برای شروع کلی، به همه عملیات‌هایی که بیشتر از ۲۰ میلی‌ثانیه طول می‌کشند نگاه کنید.
  • رشته اصلی را مسدود کنید. برای اطلاعات بیشتر، پیمایش گزارش 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 و Perfetto نمای کلی دقیقی از رشته اصلی و مدت‌زمان صرف‌شده در هر مرحله ارائه می‌دهند. برای کسب اطلاعات بیشتر درباره تجسم ردیابی‌های Perfetto، به رابط کاربری Perfetto مستندات مراجعه کنید.

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

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

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

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

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

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

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

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

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

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

محدود کردن کار در راه‌اندازی

ممکن است بار کردن برخی‌از قاب‌ها بیشتر از بقیه طول بکشد. این‌ها ترسیم‌های پرهزینه برای برنامه محسوب می‌شوند.

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

  • فازهای ترکیب‌بندی و چیدمان کند را در اولویت قرار دهید و آن‌ها را برای بهبود انتخاب کنید.
  • هر هشدار از Perfetto و هشدار از Systrace را با افزودن رویدادهای ردیابی سفارشی بررسی کنید تا ترسیم‌های پرهزینه و تأخیرها را کاهش دهید.

اندازه‌گیری داده‌های قاب

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

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

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

فعالیت اصلی برنامه‌تان ممکن است حاوی مقدار زیادی اطلاعات باشد که از منابع متعدد بار می‌شود. رابط کاربری خانه 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، به روال‌های مطلوب مراجعه کنید.