لگ در توسعه موبایل: چیست، علل و روش‌های رفع

نویسنده: IT Sectr منتشر شده: 2026-07-28 زمان مطالعه: 9 دقیقه

لگ در برنامه موبایل تأخیر قابل توجهی بین عمل کاربر و واکنش رابط است که به دلیل بار بیش از حد رشته اصلی، نشت حافظه یا عملیات غیربهینه ورودی-خروجی رخ می‌دهد. برخلاف باگ‌های مرتبط با خطاهای منطقی، لگ یک مشکل عملکرد است: برنامه به درستی اما کند کار می‌کند. طبق گزارش AppDynamics Mobile App Performance 2024، 62٪ کاربران برنامه را حذف می‌کنند اگر بیش از 3 ثانیه کند کار کند. تشخیص لگ‌ها نیاز به پروفایل‌سازی CPU، حافظه و شبکه با استفاده از Android Studio Profiler و Xcode Instruments دارد.

نکات اصلی

  • لگ — تأخیر قابل توجه رابط در هنگام کار صحیح برنامه، ناشی از مشکلات عملکرد
  • علل اصلی — مسدود شدن رشته اصلی، نشت حافظه، توقف‌های مکرر GC، پرس‌وجوهای SQL غیربهینه و فراخوانی‌های شبکه
  • تشخیص از طریق CPU Profiler، Memory Profiler و Network Profiler در Android Studio و Time Profiler در Xcode انجام می‌شود
  • رفع شامل انتقال وظایف به رشته‌های پس‌زمینه، پیاده‌سازی کش، بهینه‌سازی آداپتورها و بارگذاری تنبل داده‌ها است
  • پیشگیری — StrictMode، Main Thread Checker، صف‌های ناهمگام GCD و Kotlin Coroutines با dispatcherهای صحیح

لگ در توسعه موبایل چیست

لگ (از انگلیسی lag) در برنامه موبایل تأخیر قابل احساس ذهنی بین عمل کاربر (لمس، سوایپ، وارد کردن متن) و واکنش رابط است. از نظر فنی لگ به عنوان زمان بین رویداد ورودی و رندر کامل فریم اندازه‌گیری می‌شود: آستانه راحت — تا 100 میلی‌ثانیه، قابل توجه — از 200 میلی‌ثانیه، بحرانی — بیش از 500 میلی‌ثانیه.

تفاوت لگ با باگ و کندی

در اصطلاح کاربران «لگ می‌زند» و «کند کار می‌کند» اغلب به عنوان مترادف استفاده می‌شوند، اما از نظر فنی لگ یک تأخیر ثابت است (مثلاً 300 میلی‌ثانیه در هر کلیک)، و «کند کار می‌کند» کاهش سرعت نامتناوب است: برنامه گاهی روان کار می‌کند، گاهی یک ثانیه قفل می‌کند. باگ بر خلاف لگ به سرعت مربوط نیست، بلکه به صحت نمایش مربوط می‌شود.

تأثیر لگ بر معیارهای برنامه

Google Play و App Store شاخص‌های عملکرد را در رتبه‌بندی برنامه‌ها در نظر می‌گیرند. نرخ ANR، تعداد jank و زمان راه‌اندازی بر دیده شدن در جستجو و تبدیل نصب تأثیر می‌گذارد. برنامه با لگ‌های مداوم تا 40٪ از کاربران را پس از اولین راه‌اندازی از دست می‌دهد.

علل لگ و کندی در برنامه‌ها

لگ‌ها زمانی رخ می‌دهند که رشته اصلی UI نمی‌تواند فریم‌ها را با نرخ 60 FPS (16.6 میلی‌ثانیه به ازای هر فریم) یا 120 FPS (8.3 میلی‌ثانیه) پردازش کند. منابع اصلی تأخیر را بررسی می‌کنیم.

مسدود شدن رشته اصلی

هر عملیات همزمان در رشته UI — خواندن از SharedPreferences، کار با پایگاه داده از طریق Room بدون suspend، رمزگشایی تصویر به Bitmap — رندر فریم را مسدود می‌کند. در Android این منجر به جا افتادن فریم‌ها (jank) می‌شود، در iOS — به تأخیر رندر Core Animation.

نشت حافظه و توقف‌های مکرر GC

وقتی Garbage Collector در Android یا ARC در iOS حافظه را آزاد می‌کند، همه رشته‌ها متوقف می‌شوند. توقف‌های مکرر GC هنگام ایجاد تعداد زیادی اشیاء موقت رخ می‌دهد — مثلاً در هر فراخوانی آداپتور لیست یک نمونه جدید ViewHolder ایجاد می‌شود. این خود را به صورت پیمایش تند نشان می‌دهد.

سلسله مراتب layout سنگین

ConstraintLayoutهای تو در تو، LinearLayoutهای متعدد، Viewهای همپوشان — هر تو رفتگی زمان measure و layout pass را افزایش می‌دهد. Xcode نشان می‌دهد که سلسله مراتب عمیق لایه‌ها (بیش از 10 سطح) باعث کاهش 20-30٪ FPS می‌شود.

  • Android — requestLayout اضافی، زنجیره‌های ناکارآمد ConstraintLayout، Bitmap بزرگ بدون downscale
  • iOS — Auto Layout constraints با تضاد، CALayer سنگین، shadowPath بدون rasterization
  • Cross-platform — فراخوانی‌های همزمان HTTP در رشته UI، تجزیه JSON سنگین، تصاویر غیربهینه با وضوح بالا

چگونه تأخیرهای عملکرد را تشخیص دهیم

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

CPU Profiler در Android Studio

CPU Profiler نشان می‌دهد کدام متدها زمان پردازنده را می‌گیرند و در کدام رشته‌ها اجرا می‌شوند. اگر متدی با محاسبات سنگین در main thread اجرا شود — این ریشه مشکل است. ضبط ردیابی با sample Java Method فعال شده امکان مشاهده پشته فراخوانی را در هر لحظه و یافتن «نقاط داغ» فراهم می‌کند.

Time Profiler در Xcode Instruments

ابزار مشابه برای iOS — Time Profiler — هر میلی‌ثانیه نمونه‌هایی از پشته جمع‌آوری می‌کند و نشان می‌دهد هر متد چند درصد از زمان CPU را می‌گیرد. ترکیب با پرچم Main Thread Only فقط عملیات روی رشته اصلی را فیلتر می‌کند که مستقیماً منابع لگ را نشان می‌دهد.

Network Profiler و تحلیل درخواست‌ها

درخواست‌های کند شبکه حتی اگر رشته UI مسدود نشده باشد، احساس لگ ایجاد می‌کنند. Network Profiler در Android Studio و Network Link Conditioner در Xcode امکان شبیه‌سازی اتصال کند و بررسی رفتار برنامه در شرایط واقعی را فراهم می‌کنند. پاسخ‌های تکه‌ای بدون پیشرفت و بارهای JSON بزرگ — منابع معمول لگ‌های ظاهری.

مثال پروفایل‌سازی درخواست شبکه با OkHttp با اندازه‌گیری زمان:

kotlin
class TimingInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val start = System.nanoTime()
        val response = chain.proceed(chain.request())
        val duration = (System.nanoTime() - start) / 1_000_000
        Log.d("زمان‌بندی", "درخواست $duration میلی‌ثانیه طول کشید")
        return response
    }
}

روش‌های رفع لگ در Android و iOS

رفع لگ نیاز به کار سیستماتیک دارد: از بهینه‌سازی یک متد واحد تا تغییرات معماری. مؤثرترین تکنیک‌ها را بررسی می‌کنیم.

پردازش ناهمگام از طریق coroutines و GCD

Kotlin Coroutines با dispatcher Dispatchers.IO برای درخواست‌های شبکه و Dispatchers.Default برای محاسبات تضمین می‌کنند که رشته اصلی برای UI آزاد می‌ماند. در iOS Grand Central Dispatch با queue .global(qos: .userInitiated) برای وظایف پس‌زمینه و .main برای به‌روزرسانی UI — رویکرد استاندارد. از عملیات sync بین صف‌ها خودداری کنید.

بهینه‌سازی آداپتورها و لیست‌ها

RecyclerView در Android و UICollectionView در iOS نیاز به پیکربندی صحیح دارند: ViewHolder با حداقل ایجاد اشیاء در onBindViewHolder، DiffUtil برای محاسبه تغییرات، prefetching برای بارگذاری زودهنگام داده‌ها. در iOS از diffable data source برای به‌روزرسانی‌های متحرک بدون مدیریت دستی استفاده کنید.

کش کردن داده‌ها و تصاویر

بارگذاری همان تصویر در هر پیمایش — لگ تضمینی. Coil (Android) و Kingfisher (iOS) تصاویر را در حافظه و دیسک کش می‌کنند و نمایش فوری را در درخواست مجدد تضمین می‌کنند. برای داده‌ها از Room با لایه کش بر اساس Flow یا Combine استفاده کنید.

مثال تنظیم کش تصاویر با Coil در Android:

kotlin
val imageLoader = ImageLoader(context) {
    memoryCachePolicy(CachePolicy.ENABLED)
    diskCachePolicy(CachePolicy.ENABLED)
    crossfade(true)
    size(512, 512)
}

// بارگذاری با کش خودکار فعال
imageView.load("https://example.com/image.jpg") {
    placeholder(R.drawable.placeholder)
    error(R.drawable.error)
}

پیشگیری از لگ در مرحله توسعه

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

StrictMode در Android

StrictMode — ابزار داخلی Android که عملیات تصادفی ورودی-خروجی و فراخوانی‌های شبکه در رشته اصلی را در مرحله توسعه شناسایی می‌کند. آن را در Application.onCreate با سیاست penaltyDeath برای نقض‌های بحرانی فعال کنید. این تنها راه تضمین این است که توسعه‌دهنده مشکل را قبل از commit ببیند.

Main Thread Checker در iOS

مشابه برای iOS — Main Thread Checker در Xcode که بخشی از Runtime Sanitization است. این به طور خودکار بررسی می‌کند که همه فراخوانی‌های UIKit و AppKit از رشته اصلی انجام می‌شوند. آن را در طرح ساخت Debug فعال کنید و به هشدارهای صفر در CI برسید.

بنچمارک‌های عملکرد در CI

به خط لوله CI اجرای Macrobenchmark (Android) و XCTMetrics (iOS) را برای اندازه‌گیری زمان راه‌اندازی، FPS پیمایش و استفاده از حافظه اضافه کنید. آستانه‌ها را تعیین کنید: اگر commit جدید زمان راه‌اندازی را بیش از 5٪ افزایش دهد — ساخت ناموفق است.

  • Android — Macrobenchmark، Baseline Profiles، Jetpack Benchmark Library
  • iOS — XCTMetrics، os_signpost، MetricKit برای جمع‌آوری معیارهای دستگاه‌های کاربران
  • رویکرد کلی — پروفایل‌سازی قبل و بعد از هر تغییر مهم، تست‌های عملکرد رگرسیونی

سؤالات متداول

لگ چه تفاوتی با FPS پایین دارد؟

لگ یک احساس ذهنی تأخیر است که حتی با FPS بالا ممکن است رخ دهد اگر تأخیر ناشی از زمان پردازش ورودی باشد نه رندر. FPS پایین (کمتر از 30 فریم/ثانیه) — یکی از علل لگ است، اما نه تنها علت.

چگونه لگ را در برنامه اندازه‌گیری کنیم؟

از Frame Timing API در Android (Choreographer) و CADisplayLink در iOS برای اندازه‌گیری زمان بین فریم‌ها استفاده کنید. Google Play Vitals نرخ jank را در شرایط واقعی نشان می‌دهد. برای اندازه‌گیری‌های دقیق از Macrobenchmark با سناریوهای پیمایش استفاده کنید.

چرا لگ فقط در دستگاه‌های قدیمی ظاهر می‌شود؟

دستگاه‌های قدیمی هسته‌های CPU کمتر، RAM کمتر و حافظه کندتری دارند. عملیاتی که در یک پرچمدار 5 میلی‌ثانیه طول می‌کشد، در یک دستگاه اقتصادی ممکن است 50 میلی‌ثانیه طول بکشد. عملکرد را در دستگاه‌های پایین رده تست کنید و برای کامپایل AOT Baseline Profiles تنظیم کنید.

آیا بهینه‌سازی تصاویر می‌تواند لگ را رفع کند؟

بله، این یکی از مؤثرترین روش‌ها است. تصاویر با وضوح بالا حافظه و زمان CPU زیادی برای رمزگشایی می‌گیرند. از downscale به اندازه View، فرمت‌های WebP (Android) و HEIC (iOS) و همچنین کش از طریق Coil یا Kingfisher استفاده کنید.

SwiftUI در مقایسه با UIKit چه تأثیری بر لگ دارد؟

SwiftUI به طور خودکار به‌روزرسانی‌ها را از طریق diffing بهینه می‌کند که خطر لگ را در هنگام تغییر داده کاهش می‌دهد. با این حال سلسله مراتب پیچیده و بازسازی مکرر body می‌تواند باعث کاهش FPS شود. UIKit کنترل بیشتری بر عملکرد می‌دهد اما نیاز به بهینه‌سازی دستی دارد.

خلاصه

  • لگ — تأخیر بین عمل کاربر و واکنش رابط ناشی از مشکلات عملکرد، نه خطاهای منطقی
  • علل اصلی — مسدود شدن رشته اصلی، نشت حافظه، سلسله مراتب layout سنگین و درخواست‌های شبکه غیربهینه
  • تشخیص از طریق CPU Profiler، Memory Profiler و Network Profiler در Android؛ Time Profiler و Main Thread Checker در iOS
  • رفع شامل coroutines، GCD، بهینه‌سازی آداپتورها، کش تصاویر داده و بارگذاری تنبل
  • پیشگیری — StrictMode، Macrobenchmark، Baseline Profiles، MetricKit و تست‌های عملکرد رگرسیونی
  • اندازه‌گیری — Choreographer در Android، CADisplayLink در iOS، Google Play Vitals برای نظارت تولید
  • توصیه: CI با بررسی FPS و زمان راه‌اندازی در هر commit برای جلوگیری از رگرسیون راه‌اندازی کنید

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

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید