اپلیکیشن کند — دلیل اصلی حذف برنامهها توسط کاربران است. میلیثانیه تأخیر هنگام راهاندازی یا پیمایش لیست، retention را دهها درصد کاهش میدهد. عملکرد (performance) فقط سرعت نیست، بلکه پایداری نیز هست: عدم وجود ANR، کرشها و نشت حافظه. این مقاله تمام جنبههای عملکرد را پوشش میدهد: از مدیریت حافظه (GC, ARC) تا پروفایلینگ با ابزارها. اطلاعات بیشتر — در راهنمای رسمی Android Performance.
نکات اصلی
عملکرد اپلیکیشن مستقیماً به jank — تأخیر قابل توجه بین اقدام کاربر و پاسخ رابط کاربری — مرتبط است. دلایل اصلی: مسدود شدن نخ اصلی (عملیات سنگین روی نخ UI)، ترسیم مجدد مکرر طرحبندی (overdraw)، نشت حافظه (GC مکرر)، الگوریتمهای غیربهینه (O(n²) روی دادههای بزرگ). نرخ فریم (FPS) — تعداد فریم در ثانیه. برای تجربه راحت به 60 FPS پایدار (اندروید) یا 120 FPS (iPhone Pro, iPad Pro) نیاز است. VSync رندر را با نرخ تازهسازی صفحه همگام میکند.
Jank زمانی رخ میدهد که رندر یک فریم از 16.6 میلیثانیه (برای 60 FPS) یا 8.3 میلیثانیه (برای 120 FPS) فراتر رود. پروفایلینگ GPU (Profile GPU Rendering در اندروید، Core Animation در آیاواس) نشان میدهد کدام مراحل رندر بیشترین زمان را میگیرند. مراحل اصلی: Layout (چیدمان عناصر)، Draw (رسم)، Display (انتقال به بافر فریم). رایجترین مشکل تورم طرحبندی در XML است، به ویژه هنگام استفاده از ConstraintLayout تو در توی پیچیده.
Time-to-Interactive (TTI) — زمانی که اپلیکیشن کاملاً آماده تعامل میشود. TTI شامل شروع سرد، بارگذاری داده و مقداردهی کتابخانهها است. Google TTI را کمتر از 5 ثانیه، Apple — کمتر از 2 ثانیه برای صفحههای اصلی توصیه میکند. بارگذاری تنبل — تکنیک بارگذاری تأخیری محتوا و کتابخانهها، که برای بهبود TTI حیاتی است. در IT Sectr ما به طور پیشفرض در همه پروژهها از مقداردهی تنبل استفاده میکنیم.
ANR و کرش — دشمنان اصلی عملکرد اپلیکیشن موبایل. ANR (Application Not Responding) — کادر محاورهای در اندروید که اگر نخ اصلی بیش از 5 ثانیه مسدود شود ظاهر میشود. دلایل: درخواستهای شبکه همزمان روی نخ UI، کار با پایگاه داده بدون کوروتین، رمزگشایی بیت مپ بزرگ بدون کاهش نمونه، deadlock روی نخ اصلی. پشته فراخوانی ANR در /data/anr/traces.txt ذخیره میشود و امکان تعیین مکان دقیق مسدودیت را فراهم میکند.
کرش — پایان غیرمنتظره اپلیکیشن. در اندروید — Exception (Java/Kotlin) یا Signal (کد بومی). در آیاواس — NSException یا سیگنال (EXC_BAD_ACCESS — دسترسی به حافظه آزاد شده). ابزارهای گزارش کرش: Firebase Crashlytics, Sentry, BugSnag. آنها stacktrace، دادههای دستگاه و مراحل بازتولید را جمعآوری میکنند. Stack Overflow — سرریز پشته فراخوانی در اثر بازگشت بینهایت. OutOfMemoryError — وقتی heap پر است.
StrictMode — ابزار اندروید برای تشخیص نقض امنیت نخ. اجازه میدهد قوانینی تنظیم کنید: ThreadPolicy (منع دیسک/شبکه روی نخ اصلی)، VmPolicy (تشخیص نشت Activity, SQLite, CloseGuard). StrictMode فقط در بیلد دیباگ فعال شود — در نسخه نهایی نباید کار کند. در آیاووس معادل آن Main Thread Checker (Xcode) است که به طور خودکار فراخوانیهای UIKit را در خارج از نخ اصلی تشخیص میدهد.
نشت حافظه (Memory Leak) — موقعیتی که یک شیء در حافظه باقی میماند اگرچه اپلیکیشن دیگر از آن استفاده نمیکند. این به طور مستقیم عملکرد اپلیکیشن را کاهش میدهد. در اندروید، GC (Garbage Collection) نمیتواند شیء را جمعآوری کند اگر یک مرجع قوی به آن وجود داشته باشد. دلایل معمول: مراجع استاتیک به Activity، callback/observer لغو نشده، کلاسهای داخلی با مرجع ضمنی به کلاس خارجی، Handler با پیامهای پاکنشده. LeakCanary — کتابخانه تشخیص خودکار نشت.
ARC (Automatic Reference Counting) — مدل مدیریت حافظه در آیاواس. هر شیء یک شمارنده مرجع (retain count) دارد. وقتی شمارنده به صفر رسید، حافظه آزاد میشود. Retain Cycle زمانی رخ میدهد که دو شیء مراجع قوی به یکدیگر نگه میدارند (A → B و B → A). ARC هرگز شمارندهها را صفر نخواهد کرد. راهحل: مراجع ضعیف (weak) یا بیصاحب (unowned). Weak هنگام آزاد شدن شیء به طور خودکار nil میشود. Unowned nil نمیشود اما تضمین میکند که شیء زنده است.
GC (Garbage Collection) در اندروید (Java/Kotlin) کار میکند. GC به طور دورهای اجرا را متوقف میکند (مکث Stop-the-World) برای یافتن و آزاد کردن اشیاء غیرقابل دسترس. محرک GC: وقتی heap تا درصد مشخصی پر شود. ARC در آیاواس (Swift/Objective-C) کار میکند و مکث ندارد — شمارندهها با هر انتساب به صورت اتمی بهروز میشوند. ARC قابل پیشبینیتر است اما میتواند در فرکانس بالای انتساب، عملیات retain/release اضافی انباشته کند.
مرجع ضعیف (Weak Reference) و مرجع قوی (Strong Reference) — نوع مرجع تعیین میکند که آیا GC/ARC میتواند شیء را آزاد کند. Strong Reference — تا زمانی که این مرجع وجود دارد، شیء جمعآوری نخواهد شد. Weak Reference — GC/ARC میتواند شیء را جمعآوری کند؛ مرجع ضعیف nil میشود (در Swift/Java WeakReference). Unowned Reference (Swift) — هنگام آزاد شدن nil نمیشود؛ دسترسی به آن پس از مرگ شیء باعث کرش میشود. در اندروید برای مراجع ضعیف از java.lang.ref.WeakReference استفاده میشود.
مثال تشخیص نشت در اندروید با LeakCanary:
// Утечка: анонимный класс держит ссылку на Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val handler = object : Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
// Используем `this@MainActivity`, сохраняя ссылку на Activity
Log.d("TAG", "Handler received message")
}
}
handler.sendEmptyMessageDelayed(0, 60000)
}
}
// Исправление: статический Handler + WeakReference
class SafeHandler(activity: MainActivity) : Handler() {
private val weakActivity =
WeakReference(activity)
override fun handleMessage(msg: Message) {
weakActivity.get() ?: return
Log.d("TAG", "Handler received message")
}
}
پروفایلینگ — فرآیند اندازهگیری عملکرد اپلیکیشن: CPU، حافظه، شبکه، مصرف انرژی. بدون پروفایلینگ، بهینهسازی کورکورانه بیفایده است — نمیدانید کدام بخش کد واقعاً کند است.
| ابزار | پلتفرم | اندازهگیری | کی استفاده کنیم |
|---|---|---|---|
| Instruments (Time Profiler) | iOS | CPU، فراخوانی توابع، زمان اجرا | بهینهسازی الگوریتمها، جستجوی تنگناها |
| Instruments (Allocations) | iOS | حافظه، تعداد اشیاء، retain counts | یافتن نشت و مصرف بیش از حد حافظه |
| Instruments (Leaks) | iOS | Retain cycles، نشت حافظه | بررسی منظم قبل از انتشار |
| Android Profiler (CPU) | Android | استفاده CPU، فعالیت نخ، traces | یافتن مسدودیتهای نخ اصلی |
| Android Profiler (Memory) | Android | Heap dump، ردیابی تخصیص | یافتن نشت، تحلیل اشیاء |
| Android Profiler (Network) | Android | ترافیک، سرعت، زمانبندی درخواستها | بهینهسازی فراخوانیهای شبکه |
| LeakCanary | Android | تشخیص خودکار نشت حافظه | در تمام مراحل توسعه |
| StrictMode | Android | دیسک/شبکه روی نخ اصلی، نشت | بیلد دیباگ |
| Traceview / Systrace | Android | ردیابی متد، رویدادهای سیستم | تحلیل عمیق تأخیر |
Instruments (Xcode) — قدرتمندترین ابزار برای iOS. Time Profiler نشان میدهد کدام توابع بیشترین CPU را مصرف میکنند. Allocations ایجاد و آزادسازی اشیاء را ردیابی میکند. Leaks به طور خودکار retain cycleها را پیدا میکند. مراحل پروفایلینگ: (1) Instruments را راهاندازی کنید؛ (2) الگو را انتخاب کنید (Time Profiler برای CPU)؛ (3) سناریوی مشکلدار را اجرا کنید؛ (4) پشته فراخوانی را تحلیل کنید — پهنترین ستون داغترین تابع است.
Android Profiler در Android Studio تعبیه شده است (View → Tool Windows → Profiler). CPU Profiler بار هر نخ را نشان میدهد. Memory Profiler — heap dump و ردیابی تخصیص. Network Profiler — تمام درخواستهای HTTP با زمانبندی. Energy Profiler — مصرف انرژی: WakeLock, Location, Network. برای ردیابی دقیق از Systrace (Android 10+) یا Perfetto — ردیابی سیستم با دقت میکروثانیه استفاده میشود.
راهاندازی اپلیکیشن یکی از شاخصهای کلیدی عملکرد است. به سه نوع تقسیم میشود: شروع سرد — اپلیکیشن از صفر راهاندازی میشود: فرآیند ایجاد میشود، Application.onCreate (اندروید) / AppDelegate.applicationDidFinishLaunching (آیاواس)، بارگذاری کلاسها، مقداردهی کتابخانهها. شروع گرم — فرآیند وجود دارد اما Activity/ViewController از بین رفته است (مثلاً هنگام چرخش صفحه یا بازگشت از حافظه). شروع داغ — Activity/ViewController در حافظه است، اپلیکیشن به سادگی نمایش داده میشود (تعویض از اپلیکیشن دیگر).
شروع سرد مهمترین معیار است. در اندروید شامل: (1) launch Activity — بارگذاری XML، مقداردهی View؛ (2) اولین فریم — زمان تا اولین رندر. Google توصیه میکند: launch Activity < 200 میلیثانیه، اولین فریم < 500 میلیثانیه، TTI < 5 ثانیه. بهینهسازی شروع سرد: کاهش Application.onCreate (کوروتین برای مقداردهی تنبل)، استفاده از SplashScreen API (Android 12+)، به تأخیر انداختن مقداردهی کتابخانهها (WorkManager, DI)، حذف ContentProviders اضافی.
در آیاواس، شروع سرد شامل: بارگذاری باینری Mach-O، dyld (پیونددهنده پویا)، مقداردهی runtime Objective-C، delegate برنامه، اولین کنترلر. Chrome Custom Tabs (اندروید) و Universal Links (آیاواس) — فناوریهایی برای باز کردن سریع محتوای خارجی در اپلیکیشن بدون شروع سرد کامل. توصیه میشود شروع سرد را روی دستگاههای واقعی میانرده آزمایش کنید.
اندازه اپلیکیشن — عامل عملکرد برای نصب و بهروزرسانیها. بر نرخ تبدیل تأثیر میگذارد: هر 10 MB نرخ تبدیل را 1% کاهش میدهد. Google Play توصیه میکند اندازه APK کمتر از 150 MB؛ App Store — کمتر از 200 MB (شبکههای سلولی — 100 MB). روشهای اصلی بهینهسازی: فشردهسازی تصاویر (WebP به جای PNG 25-35% صرفهجویی), برداریسازی (VectorDrawable در اندروید، SF Symbols در آیاواس), حذف کد استفادهنشده (R8/ProGuard), حذف منابع استفادهنشده (lint → unused resources).
App Bundle (اندروید) — قالب انتشار که در آن Google Play برای هر دستگاه APK بهینهشده تولید میکند. App Bundle اندازه دانلود را 20-40% کاهش میدهد. Dynamic Delivery — ماژولهایی که بر اساس تقاضا دانلود میشوند (on-demand feature modules). در آیاواس معادل آن On-Demand Resources (ODR) است: منابعی که پس از اولین راهاندازی دانلود میشوند (سطوح بازی، ویدئوها).
بارگذاری تنبل — تکنیکی که در آن ماژولها و کتابخانهها در راهاندازی بارگذاری نمیشوند، بلکه در صورت نیاز بارگذاری میشوند. Split APK (اندروید) و App Slicing (آیاواس) — تقسیم اپلیکیشن به اسلاتهای معماری: arm64-v8a, x86_64. بهینهسازی اندازه اپلیکیشن — یک فرآیند مداوم: ترکیب APK را تجزیه و تحلیل کنید (Analyze APK در Android Studio)، آیکونهای تکراری را حذف کنید، به جای چندین چگالی PNG از SVG استفاده کنید. در IT Sectr ما بررسی اندازه بیلد را در CI/CD برای هر MR وارد میکنیم.
سوالات متداول
ANR (Application Not Responding) — کادر محاورهای که در اندروید ظاهر میشود اگر نخ اصلی بیش از 5 ثانیه مسدود شود. برای جلوگیری از ANR، تمام عملیات سنگین (شبکه، پایگاه داده، پردازش فایل) را به نخهای پسزمینه منتقل کنید. معادل در آیاواس frozen UI است، وقتی اپلیکیشن به لمسها پاسخ نمیدهد.
نشت حافظه — وقتی یک شیء نمیتواند آزاد شود زیرا مراجعی به آن وجود دارد. Retain Cycle — موقعیتی در iOS/Objective-C که دو شیء به یکدیگر ارجاع میدهند (A → B → A) و ARC نمیتواند هیچکدام را آزاد کند. راهحل: مراجع weak/unowned و پاکسازی بهموقع callbackها.
برای iOS: Instruments (Time Profiler, Allocations, Leaks). برای اندروید: Android Profiler (CPU, Memory, Network), LeakCanary (نشت حافظه), StrictMode (نقض نخ). توصیه میشود پروفایلینگ را در طول توسعه و یکپارچهسازی ترکیب کنید.
شروع سرد — اپلیکیشن از صفر شروع میشود: فرآیند ایجاد، کلاسها بارگذاری، Application.onCreate اجرا میشود. شروع گرم — فرآیند وجود دارد اما Activity/ViewController بازآفرینی میشود. شروع داغ — Activity/ViewController از قبل در حافظه است، فقط نمایش داده میشود. شروع سرد کندترین است (1-5 ثانیه) و برای تجربه کاربری حیاتی است.
روشهای اصلی: حذف منابع و کد استفادهنشده (از R8/ProGuard استفاده کنید)، برداریسازی تصاویر (VectorDrawable, SF Symbols)، فشردهسازی PNG/WebP (اندروید)، استفاده از App Bundle به جای APK، حذف کتابخانههای غیرضروری، استفاده از بارگذاری تنبل برای ماژولها. بهینهسازی اندازه میتواند APK را 40-60% کاهش دهد.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.