این سند به شما کمک میکند تا مشکلات کلیدی عملکرد در برنامه خود را شناسایی و برطرف کنید.
مسائل کلیدی عملکرد
مشکلات زیادی وجود دارد که میتواند به عملکرد ضعیف یک برنامه منجر شود، اما موارد زیر برخی از مشکلات رایجی هستند که باید به دنبال آنها باشید:
- تأخیر راهاندازی
تأخیر راهاندازی، مدت زمانی است که بین ضربه زدن روی آیکون برنامه، اعلان یا سایر نقاط ورود و نمایش دادههای کاربر روی صفحه طول میکشد.
اهداف اولیه زیر را در برنامههای خود دنبال کنید:
- شروع سرد در کمتر از ۵۰۰ میلیثانیه. شروع سرد زمانی اتفاق میافتد که برنامه در حال اجرا در حافظه سیستم وجود نداشته باشد. این اتفاق زمانی میافتد که برنامه برای اولین بار پس از راهاندازی مجدد یا از زمانی که فرآیند برنامه توسط کاربر یا سیستم متوقف شده است، اجرا میشود. شروع سرد بیشترین کار را از سیستم میطلبد، زیرا باید همه چیز را از حافظه بارگیری کرده و برنامه را مقداردهی اولیه کند. سعی کنید شروع سرد ۵۰۰ میلیثانیه یا کمتر طول بکشد.
- شروع گرم در کمتر از ۲۰۰ میلیثانیه و شروع داغ در کمتر از ۱۵۰ میلیثانیه. شروع گرم زمانی اتفاق میافتد که فرآیند برنامه در پسزمینه در حال اجرا است، اما سیستم نیاز دارد رابط کاربری را دوباره مقداردهی اولیه کند یا فعالیت را به پیشزمینه بازگرداند، مانند زمانی که کاربر از برنامه خارج میشود و کمی بعد آن را دوباره باز میکند. شروع گرم حتی سریعتر است زیرا فعالیت برنامه از قبل در حافظه پنهان شده است و فقط باید به پیشزمینه آورده شود، بدون نیاز به ایجاد مجدد سلسله مراتب نما. هدف این است که شروع گرم زیر ۲۰۰ میلیثانیه و شروع داغ زیر ۱۵۰ میلیثانیه نگه داشته شود.
- تأخیرهای P95 و P99 بسیار نزدیک به تأخیر متوسط هستند. P95 و P99 نشاندهنده صدکهای نود و پنجم و نود و نهم زمانهای راهاندازی هستند، در حالی که میانه، صدک پنجاهم است. وقتی شروع برنامه زمان زیادی طول میکشد، تجربه کاربری ضعیفی ایجاد میشود. ارتباطات بین پردازشی (IPC) و ورودی/خروجیهای غیرضروری در طول مسیر بحرانی راهاندازی برنامه میتوانند باعث ایجاد تداخل در قفل شوند و ناسازگاریهایی را ایجاد کنند.
- اسکرول جانک
جنک اصطلاحی است که به وقفه بصری اشاره دارد و زمانی رخ میدهد که سیستم قادر به ساخت و ارائه فریمها به موقع برای نمایش آنها در صفحه با سرعت درخواستی ۶۰ هرتز یا بالاتر نیست. جنک بیشتر هنگام اسکرول کردن آشکار میشود، زمانی که به جای جریان روان انیمیشن، وقفههایی وجود دارد. جنک زمانی ظاهر میشود که حرکت در طول مسیر برای یک یا چند فریم متوقف میشود، زیرا برنامه برای رندر محتوا بیشتر از مدت زمان یک فریم در سیستم زمان میبرد.
Target 90Hz refresh rates in your apps. Conventional rendering rates are 60Hz, but many newer devices operate in 90Hz mode during user interactions, such as scrolling. Some devices support even higher rates of up to 120Hz.
برای مشاهدهی نرخ نوسازی (Refresh Rate) دستگاه در یک زمان مشخص، با استفاده از گزینهی Developer Options > Show refresh rate در بخش Debugging ، یک گزینهی همپوشانی (overlay) را فعال کنید.
- گذارهایی که روان نیستند
این موضوع در طول تعاملاتی مانند جابجایی بین تبها یا بارگذاری یک فعالیت جدید آشکار میشود. این نوع انتقالها باید انیمیشنهای روان باشند و شامل تأخیر یا لرزش بصری نباشند.
- ناکارآمدیهای برق
انجام کار، شارژ باتری و در نهایت عمر آن را کاهش میدهد.
Memory allocations, which come from creating new objects in code, cause work in the system. Not only do the allocations themselves require effort from the Android Runtime (ART), but freeing these objects later ( garbage collection ) also requires time and effort.
تخصیص حافظه و جمعآوری زباله، به خصوص برای اشیاء موقت، بسیار سریعتر و کارآمدتر شدهاند. اگرچه قبلاً بهترین روش این بود که تا حد امکان از تخصیص اشیاء خودداری شود، اما توصیه میکنیم کاری را انجام دهید که برای برنامه و معماری شما منطقیتر است. با توجه به قابلیتهای ART، صرفهجویی در تخصیصها با ریسک کد غیرقابل نگهداری، بهترین روش نیست.
با این حال، تخصیصها نیاز به تلاش دارند، بنابراین به خاطر داشته باشید که اگر اشیاء زیادی را در حلقه داخلی خود تخصیص میدهید، میتوانند به مشکلات عملکردی منجر شوند.
شناسایی مسائل
برای رفع مشکلات عملکرد، مسیرهای حیاتی کاربر زیر را شناسایی و بررسی کنید:
- جریانهای راهاندازی رایج، از جمله از لانچر و اعلان.
- صفحاتی که کاربر در آنها دادهها را پیمایش میکند.
- انتقال بین صفحه نمایش ها.
- جریانهای طولانی مدت، مانند ناوبری یا پخش موسیقی.
برای هر یک از این جریانها، با استفاده از ابزارهای اشکالزدایی زیر، آنچه اتفاق میافتد را بررسی کنید:
- Perfetto : به شما امکان میدهد با دادههای زمانبندی دقیق، ببینید چه اتفاقی در کل دستگاه میافتد.
- Memory Profiler : به شما امکان میدهد ببینید چه تخصیصهای حافظهای روی هیپ اتفاق میافتد.
- Simpleperf : shows a flamegraph of what function calls are using the most CPU during a certain period of time. When you identify something that's taking a long time in Systrace, but you don't know why, Simpleperf can provide additional information.
To understand and debug these performance issues, it's critical to manually debug individual test runs. You can't replace the preceding steps by analyzing aggregated data. However, to understand what users are actually seeing and identify when regressions might occur, it's important to set up metrics collection in automated testing and in the field:
- جریانهای استارتاپی
- معیارهای میدانی: زمان راهاندازی کنسول Play
- تستهای آزمایشگاهی: راهاندازی آزمایشی با Macrobenchmark
- جانک
- معیارهای میدانی
- نکات مهم در مورد فریم کنسول بازی: در کنسول بازی، نمیتوانید معیارها را به یک مسیر کاربری خاص محدود کنید. این کنسول فقط گزارشهای کلی از مشکلات در سراسر برنامه را ارائه میدهد.
- اندازهگیری سفارشی با
FrameMetricsAggregator: میتوانیدFrameMetricsAggregatorبرای ثبت معیارهای ناخواسته در طول یک گردش کار خاص استفاده کنید.
- تستهای آزمایشگاهی
- پیمایش با Macrobenchmark
- Macrobenchmark collects frame timing using
dumpsys gfxinfocommands that bracket a single user journey. This is a way to understand variation in jank over a specific user journey. TheRenderTimemetrics, which highlight how long frames are taking to draw, are more important than the count of janky frames for identifying regressions or improvements.
- معیارهای میدانی
مشکلات تأیید لینکهای برنامه
پیوندهای برنامه، پیوندهای عمیقی هستند که بر اساس URL وبسایت شما ایجاد میشوند و تأیید شدهاند که به وبسایت شما تعلق دارند. تأیید پیوندهای برنامه میتوانند به دلایل زیر با شکست مواجه شوند:
- محدودههای نادرست فیلتر اینتنت: فقط برای URLهایی که برنامه شما میتواند به آنها پاسخ دهد،
autoVerifyبه فیلترهای اینتنت اضافه کنید. - Unverified protocol switches: unverified server-side and subdomain redirects are considered security risks and fail verification. They cause all
autoVerifylinks to fail. For example, redirecting links from HTTP to HTTPS, such as example.com to www.example.com, without verifying the HTTPS links can cause fail verification. Make sure to verify App Links by adding intent filters. - پیوندهای غیرقابل تأیید: اضافه کردن پیوندهای غیرقابل تأیید برای اهداف آزمایشی میتواند باعث شود سیستم پیوندهای برنامه شما را تأیید نکند.
- سرورهای غیرقابل اعتماد: مطمئن شوید که سرورهای شما میتوانند به برنامههای کلاینت شما متصل شوند.
برنامه خود را برای تجزیه و تحلیل عملکرد تنظیم کنید
It's essential to properly set up to get accurate, repeatable, actionable benchmarks from an app. Test on a system that is as close to production as possible, while suppressing sources of noise. The following sections show a number of APK- and system-specific steps you can take to prepare a test setup, some of which are use-case specific.
نقاط ردیابی
برنامهها میتوانند کد خود را با رویدادهای ردیابی سفارشی، ابزارسازی کنند.
While traces are being captured, tracing does incur a small overhead of roughly 5μs per section, so don't put it around every method. Tracing larger chunks of work, >0.1ms, can give significant insights into bottlenecks.
ملاحظات APK
Debug variants can be helpful for troubleshooting and symbolizing stack samples, but they have severe impacts on performance. Devices running Android 10 (API level 29) and higher can use profileable android:shell="true" in their manifest to enable profiling in release builds.
Use your production-grade code shrinking configuration. Depending on the resources your app uses, this can have a substantial impact on performance. Some ProGuard configurations remove tracepoints, so consider removing those rules for the configuration you're running tests on.
گردآوری
Compile your app on-device to a known state—generally speed for simplicity, or speed-profile to more closely match production performance (though this requires warming up the application and dumping profiles or compiling the app's baseline profiles).
Both speed and speed-profile reduce the amount of code running interpreted from dex, and consequently the amount of background just-in-time (JIT) compilation which can cause significant interference. Only speed-profile reduces the impact of runtime class loading from dex.
دستور زیر برنامه را با استفاده از حالت speed کامپایل میکند:
adb shell cmd package compile -m speed -f com.example.packagename
حالت کامپایل speed متدهای برنامه را به طور کامل کامپایل میکند. حالت speed-profile متدها و کلاسهای برنامه را طبق پروفایلی از مسیرهای کد استفاده شده که در طول استفاده از برنامه جمعآوری میشود، کامپایل میکند. جمعآوری پروفایلها به طور مداوم و صحیح میتواند دشوار باشد، بنابراین اگر تصمیم به استفاده از آنها دارید، مطمئن شوید که آنها آنچه را که انتظار دارید جمعآوری میکنند. پروفایلها در مکان زیر قرار دارند:
/data/misc/profiles/ref/[package-name]/primary.prof
ملاحظات سیستم
For low-level and high-fidelity measurements, calibrate your devices. Run A/B comparisons across the same device and same OS version. There can be significant variations in performance, even across the same device type.
در دستگاههای روتشده، استفاده از اسکریپت lockClocks را برای Microbenchmarks در نظر بگیرید. این اسکریپتها از جمله موارد زیر را انجام میدهند:
- CPU ها را در یک فرکانس ثابت قرار دهید.
- هستههای کوچک را غیرفعال کنید و GPU را پیکربندی کنید.
- تنظیم دمایی را غیرفعال کنید.
We don't recommend using a lockClocks script for user-experience focused tests such as app launch, DoU testing, and jank testing, but it can be essential for reducing noise in Microbenchmark tests.
در صورت امکان، استفاده از یک چارچوب آزمایشی مانند Macrobenchmark را در نظر بگیرید که میتواند نویز را در اندازهگیریهای شما کاهش داده و از عدم دقت اندازهگیری جلوگیری کند.
شروع کند برنامه: فعالیت غیرضروری ترامپولین
A trampoline activity can extend app startup time unnecessarily, and it's important to be aware if your app is doing it. As shown in the following example trace, one activityStart is immediately followed by another activityStart without any frames being drawn by the first activity.
شکل ۱. ردی که فعالیت ترامپولین را نشان میدهد.
This can happen both in a notification entrypoint and a regular app startup entrypoint, and you can often address it by refactoring. For example, if you're using this activity to perform setup before another activity runs, factor this code out into a reusable component or library.
تخصیصهای غیرضروری که باعث ایجاد GCهای مکرر میشوند
ممکن است در یک Systrace شاهد وقوع مکرر عملیات جمعآوری زباله (GC) باشید.
در مثال زیر، جمعآوری زباله هر 10 ثانیه در طول یک عملیات طولانی مدت، نشانهای است که برنامه ممکن است در طول زمان به طور غیر ضروری اما مداوم تخصیص دهد:
شکل ۲. ردیابی که فاصله بین رویدادهای GC را نشان میدهد.
You might also notice in Memory Profiler that a specific call stack is making the vast majority of the allocations. You don't need to eliminate all allocations aggressively, as this can make code harder to maintain. Instead, start by working on hotspots of allocations.
قابهای بیکیفیت
The graphics pipeline is relatively complicated, and there can be some nuance in determining whether a user ultimately might see a dropped frame. In some cases, the platform can "rescue" a frame using buffering. However, you can ignore most of that nuance to identify problematic frames from your app's perspective.
وقتی فریمها با کار کمی از سوی برنامه ترسیم میشوند، نقاط ردیابی Choreographer.doFrame() با سرعت ۱۶.۷ میلیثانیه در دستگاهی با نرخ ۶۰ فریم بر ثانیه رخ میدهند:
شکل ۳. ردیابی که فریمهای سریع مکرر را نشان میدهد.
اگر زوم کنید و در طول مسیر حرکت کنید، گاهی اوقات میبینید که فریمها کمی بیشتر طول میکشند تا کامل شوند، اما بیشتر از زمان اختصاص داده شده ۱۶.۷ میلیثانیه نیستند. این فریمها مشکلی ندارند:
شکل ۴. ردیابی که فریمهای سریع مکرر را با انفجارهای دورهای کار نشان میدهد.
وقتی اختلالی در این ریتم منظم مشاهده میکنید، مانند شکلهای ۵ و ۶، یک فریم نامنظم ایجاد میشود:
شکل ۵. ردیابی که یک قاب خراب را نشان میدهد.
شکل ۶. ردیابی که فریمهای بیکیفیت بیشتری را نشان میدهد.
در برخی موارد، برای اطلاعات بیشتر در مورد اینکه کدام اجزای رابط کاربری توسط Compose بهروزرسانی میشوند یا مانند شکل 6، برای اینکه بدانید یک LazyColumn چه کاری انجام میدهد، باید روی یک نقطه ردیابی زوم کنید. هنگام تشخیص این گلوگاههای رابط کاربری، ردیابی استاندارد سیستم ممکن است نشان ندهد که کدام composableها علت اصلی هستند. در این موارد، از ردیابی ترکیب Jetpack Compose استفاده کنید، که توابع composable دقیق را مستقیماً در داخل ردیابی نشان میدهد و تشخیص ترکیبهای غیرمنتظره را آسانتر میکند. شکلهای 5 و 6 نتایج ردیابی ترکیب را نشان میدهند.
For more information about optimizing Compose performance, see Jetpack Compose Performance . For more information about identifying janky frames and debugging their causes, see Slow rendering .
اشتباهات رایج در چیدمان با تنبلی
Invalidating the entire backing state of a lazy layout unnecessarily can lead to excessive recompositions, long frame rendering times, and jank. To minimize the number of list items that need to update, use item keys for your items and only mutate the specific state elements that change.
برای روشهای جلوگیری از تخصیص مجدد پرهزینهی کل فهرست، که باعث بهروزرسانی محتوا به جای جایگزینی کامل آن میشود، به بخش «استفاده از کلیدهای طرحبندی تنبل» مراجعه کنید.
Improper implementation of nested scrolling lists can cause performance drops. Avoid nesting a scrolling lazy layout inside another scrolling container without explicit constraints. For more information, see Avoid nesting components scrollable in the same direction .
عدم پیشواکشی کافی دادهها، یا عدم پیشواکشی به موقع، میتواند رسیدن به انتهای لیست پیمایش را زمانی که کاربر نیاز به انتظار برای دادههای بیشتر از سرور دارد، ناخوشایند کند. اگرچه این از نظر فنی بیاحتیاطی نیست، زیرا هیچ مهلت فریمی از دست نمیرود، اما میتوانید با تغییر زمان و مقدار پیشواکشی، تجربه کاربری را به طور قابل توجهی بهبود بخشید تا کاربر مجبور نباشد برای دادهها منتظر بماند.
اشکالزدایی برنامه شما
در ادامه روشهایی برای اشکالزدایی عملکرد برنامه شما ارائه شده است.
اشکالزدایی هنگام راهاندازی برنامه با Systrace
برای مرور کلی فرآیند راهاندازی برنامه، به بخش زمان راهاندازی برنامه مراجعه کنید و برای مرور کلی ردیابی سیستم و استفاده از پروفایلر اندروید استودیو، ویدیوی زیر را ببینید.
شما میتوانید انواع استارتآپها را در مراحل زیر مشخص کنید:
- راهاندازی سرد: با ایجاد یک فرآیند جدید بدون هیچ وضعیت ذخیرهشدهای آغاز میشود.
- راهاندازی گرم: یا فعالیت را هنگام استفاده مجدد از فرآیند بازسازی میکند یا فرآیند را با حالت ذخیره شده بازسازی میکند.
- راهاندازی داغ: فعالیت را مجدداً آغاز میکند و با تورم شروع میشود.
We recommend capturing Systraces with the System Tracing app on the device . For Android 10 and higher, use Perfetto . For Android 9 and lower, use Systrace . We also recommend viewing trace files with the web-based Perfetto trace viewer . For more information, see Overview of system tracing .
برخی از مواردی که باید به دنبال آنها باشید شامل موارد زیر است:
- رقابت بر سر مانیتور: رقابت برای منابع تحت حفاظت مانیتور میتواند باعث تأخیر قابل توجه در شروع برنامه شود.
Synchronous binder transactions: look for unnecessary transactions in your app's critical path. If a necessary transaction is expensive, consider working with the associated platform team to make improvements.
GC همزمان: این مورد رایج و نسبتاً کمتأثیر است، اما اگر اغلب با آن مواجه میشوید، بررسی آن با استفاده از پروفایلر حافظه اندروید استودیو را در نظر بگیرید.
ورودی/خروجی: ورودی/خروجیهای انجامشده در طول راهاندازی را بررسی کنید و به دنبال وقفههای طولانی باشید.
فعالیت قابل توجه در سایر نخها: این موارد میتوانند با نخ رابط کاربری تداخل داشته باشند، بنابراین هنگام راهاندازی مراقب کارهای پسزمینه باشید.
توصیه میکنیم برای بهبود گزارشدهی معیار راهاندازی برنامه، هنگام تکمیل راهاندازی، تابع reportFullyDrawn فراخوانی کنید. برای اطلاعات بیشتر در مورد استفاده از reportFullyDrawn به بخش «زمان نمایش کامل» مراجعه کنید. میتوانید زمانهای شروع تعریفشده توسط RFD را از طریق پردازنده ردیابی Perfetto استخراج کنید و یک رویداد ردیابی قابل مشاهده توسط کاربر منتشر میشود.
استفاده از ردیابی سیستم روی دستگاه
You can use the system-level app called System Tracing to capture a system trace on a device . This app lets you record traces from the device without having to plug it in or connect it to adb .
استفاده از پروفایلر حافظه اندروید استودیو
شما میتوانید از ابزار پروفایل حافظه اندروید استودیو برای بررسی فشار حافظه که ممکن است ناشی از نشت حافظه یا الگوهای استفاده نادرست باشد، استفاده کنید. این ابزار، نمای زندهای از تخصیص اشیاء را ارائه میدهد.
شما میتوانید مشکلات حافظه در برنامه خود را با استفاده از Memory Profiler برای ردیابی دلیل و تعداد دفعات وقوع GCها برطرف کنید.
برای پروفایل کردن حافظه برنامه، مراحل زیر را انجام دهید:
مشکلات حافظه را تشخیص دهید.
یک جلسه پروفایل حافظه از سفر کاربری که میخواهید روی آن تمرکز کنید، ضبط کنید. همانطور که در شکل ۷ نشان داده شده است، به دنبال افزایش تعداد اشیاء باشید که در نهایت منجر به GCها میشود، همانطور که در شکل ۸ نشان داده شده است.
شکل ۷. افزایش تعداد اشیاء.
شکل ۸. جمعآوری زباله.بعد از اینکه مسیر کاربر که باعث افزایش فشار حافظه میشود را شناسایی کردید، علل ریشهای فشار حافظه را تحلیل کنید.
نقاط حساس فشار حافظه را تشخیص دهید.
همانطور که در شکل 9 نشان داده شده است، یک محدوده را در جدول زمانی انتخاب کنید تا هم Allocations و هم Shallow Size را به صورت بصری مشاهده کنید.
شکل ۹. مقادیر مربوط به تخصیصها و اندازه سطحی .روشهای مختلفی برای مرتبسازی این دادهها وجود دارد. در ادامه چند مثال از اینکه چگونه هر دیدگاه میتواند به شما در تحلیل مشکلات کمک کند، آورده شده است.
مرتبسازی بر اساس کلاس : زمانی مفید است که میخواهید کلاسهایی را پیدا کنید که اشیاء تولید میکنند که در غیر این صورت در یک مخزن حافظه ذخیره میشوند یا دوباره استفاده میشوند.
برای مثال، اگر یک برنامه در هر ثانیه ۲۰۰۰ شیء از یک کلاس خاص ایجاد کند، تعداد تخصیصها را در هر ثانیه ۲۰۰۰ واحد افزایش میدهد و شما این را هنگام مرتبسازی بر اساس کلاس مشاهده میکنید. اگر میخواهید از این اشیاء دوباره استفاده کنید تا از تولید زباله جلوگیری شود، یک استخر حافظه پیادهسازی کنید.
مرتبسازی بر اساس callstack : زمانی مفید است که میخواهید مسیری را پیدا کنید که حافظه در آن تخصیص داده میشود، مانند داخل یک حلقه یا داخل یک تابع خاص که کار تخصیص زیادی انجام میدهد.
Shallow Size : فقط حافظه خود شیء را ردیابی میکند. این برای ردیابی کلاسهای سادهای که عمدتاً از مقادیر اولیه تشکیل شدهاند، مفید است.
اندازه حفظشده : کل حافظه مربوط به خود شیء به علاوه هرگونه ارجاعی که صرفاً توسط شیء ارجاع داده شده است را نشان میدهد. این برای ردیابی فشار حافظه ناشی از اشیاء پیچیده مفید است. برای به دست آوردن این مقدار، یک dump کامل از حافظه بگیرید، همانطور که در شکل 10 نشان داده شده است. اندازه حفظشده به عنوان یک ستون اضافه میشود، همانطور که در شکل 11 نشان داده شده است.
شکل ۱۰. تخلیه کامل حافظه. 
شکل ۱۱. ستون اندازه حفظشده.
اندازهگیری تأثیر یک بهینهسازی
GCها مشهودتر و اندازهگیری تأثیر بهینهسازیهای حافظه آسانتر هستند. وقتی یک بهینهسازی فشار حافظه را کاهش میدهد، GCهای کمتری را مشاهده میکنید.
برای اندازهگیری تأثیر بهینهسازی، در جدول زمانی پروفایلر، زمان بین GCها را اندازهگیری کنید. تأثیر مثبت منجر به زمان طولانیتر بین GCها میشود.
تأثیرات نهایی بهبود حافظه به شرح زیر است:
- اگر برنامه دائماً با فشار حافظه مواجه نشود، احتمالاً تعداد دفعات خاموش شدن به دلیل کمبود حافظه کاهش مییابد.
- داشتن GC های کمتر، به خصوص در P99، معیارهای jank را بهبود میبخشد. دلیل این امر این است که GC ها باعث ایجاد درگیری CPU میشوند که میتواند منجر به تعویق افتادن وظایف رندرینگ در حین انجام GC شود.
برای شما توصیه میشود
- توجه: متن لینک زمانی نمایش داده میشود که جاوا اسکریپت غیرفعال باشد.
- تحلیل و بهینهسازی شروع به کار اپلیکیشن {:#app-startup-analysis-optimization}
- قابهای یخزده
- یک ماکروبنچمارک بنویسید