লেগ করা হল ব্যবহারকারীর বর্ণনা এই পরিস্থিতির যেখানে একটি মোবাইল অ্যাপ ধীরে ও অস্থিরভাবে চলে: কখনো সাধারণভাবে সাড়া দেয়, কখনো হঠাৎ কয়েক সেকেন্ডের জন্য জমে যায়। প্রায়োগিক প্রসঙ্গে, “লেগ করা” মানে বারংবার GC বিরতির কারণে হওয়া লেগ ও মাইক্রো-ফ্রিজ়ের সমম্বায়, মূল থ্রেড সিংক্রোনাংস অপারেশনে অবরুদ্ধ ও অপদক্ষ ডেটা গঠন। Android Performance Benchmarking Guide অনুযায়ী, প্রতিক্রিয়া সময় 300 মিলিসেকেন্ড থেকে 100 মিলিসেকেন্ড কমালে ব্যবহারকারী ধরে রাখা 25% বেড়ে যায়। লেগ করা নির্ণের জন্য CPU ও মেমরি প্রোফাইলিং এবং আবজরজন সংগ্রহের ফ্রিকোয়েন্সি বিশ্লেষণের সমন্বয় প্রয়োজন।
মূখ্য বিষয়
লেগ করা একটি অনৌপচারিক পরিভাষা যা ব্যবহারকারীরা ব্যবহার করে ব্যক্তিগতভাবে ধীর অ্যাপ পরিবেশন বর্ণনা করতে। লেগের বিপরীতে, যা একটি নিরন্তর বিলম্ব হিসাবে প্রকাশ পায়, লেগ করা অনিয়মিত জমা যাওয়া নিয়ে গঠিত: অ্যাপটি কয়েক সেকেন্ড নির্ভুলভাবে কাজ করতে পারে ও তারপর হঠাৎ 1–3 সেকেন্ডের জন্য “চিন্তা করতে” পারে।
প্রোফাইলিং দৃষ্টিকোণ থেকে, লেগ করা হারানো ফ্রেম (jank) এর একটি ধারাবাহিকতা হিসাবে প্রকাশ পায় যার শীর্ষ বিলম্ব 100 মিলিসেকেন্ড অতিক্রম করে। FPS গ্রাফে, এটি ধারদ্বারা পতন হিসাবে দেখায়: 60 → 20 → 55 → 10 ফ্রেম প্রতি সেকেন্ড। সমানভাবে কম FPS বিশিষ্ট লেগের বিপরীতে, লেগ করার স্পষ্ট পরিবর্তনশীলতা রয়েছে।
যখন একটি অ্যাপ লেগ করে, ব্যবহারকারী মন্থরতার যুক্তি বুঝতে পারে না: স্ক্রিন মোটামুটি স্ক্রল হতে পারে ও তারপর হঠাৎ এক সেকেন্ডের জন্য থেমে যেতে পারে। এটি হতাশার কারণ হয় ও অ্যাপের প্রতি আস্থা হ্রাস করে। Google এর মতে, 53% ব্যবহারকারী একটি সাইট বা অ্যাপ ত্যাগ করে যদি লোড হতে 3 সেকেন্ডের বেশি সময় লাগে।
লেগ করার অনিয়মিত প্রকৃতি ইংগিত করে যে সমস্যাটি নিরন্তর ওভারলোডের পরিবর্তে ইভেন্ট-চালিত কারকের কারণে হয়। আসুন নির্দিষ্ট পরিদৃশ্যগুলি দেখি।
Android এ, ART রানটাইমে, আবজরজন সংগ্রহ অ্যাপের সকল থ্রেড বন্ধ করে দেয়। যদি কোড অনেক অস্থায়ী অবজেক্ট তৈরি করে — উদাহরণস্বরূপ, প্রতিটি onBindViewHolder কলে কন্কাটেনেশনের মাধ্যমে একটি নতুন String তৈরি করা — GC অধিক বার চলে। হীপ আকার ও অবজেক্ট প্রজন্মের উপর নির্ভর করে একটি বিরতি 5–50 মিলিসেকেন্ড স্থায়ী হতে পারে। ব্যবহারকারী এটিকে হঠাৎ “চিন্তাশীলতা” হিসাবে অনুভব করে।
Android এ Room ও iOS এ Core Data অ্যাসিংক্রোনাংস ক্যোরি সমর্থন করে, কিন্তু ডিভেলপাররা সরলতার জন্য প্রায়শই getValue() ডাকে বা runBlocking এর মাধ্যমে ক্যোরি চালায়। 10,000 সারির একটি টেবিলে জয়েনের সাথে একটি ভারী SELECT এ 200–500 মিলিসেকেন্ড লাগতে পারে, সেই সময়ের জন্য UI সম্পূর্ণরূপে অবরুদ্ধ করে।
একটি ক্যামেরা ইমেজ (12 MP, 4000x3000 পিক্সেল) স্কেলিং ছাড়া লোড করতে Bitmap ডিকোডিংএ 200 মিলিসেকেন্ড পর্যন্ত লাগতে পারে। যদি ইমেজগুলি অ্যাসিংক্রোনাংসভাবে লোড করা হয় কিন্তু একটি সীমাবদ্ধ থ্রেড পূল ছাড়া, তবে যুগপত্বে 5–6 ডিকোড চালালে CPU ওভারলোড হতে পারে, যা স্থানান্তরিত মন্থরতা সৃষ্টি করে।
অনিয়মিত মন্থরতা নির্ণয় নিরন্তর লেগ নির্ণয়ের চেয়ে কঠিন কারণ প্রতিটি চালুতে সমস্যাটি পুনরায় না-ও হতে পারে। দীর্ঘ সময় ধরে পরিসংখ্যান সংগ্রহ করা প্রয়োজন।
Android Studio Memory Profiler শুধু মেমরি ব্যবহারই নয়, GC ইভেন্টও দেখায়: ফ্রিকোয়েন্সি, ধরন (Concurrent, Full), ডেরেশন। নিষ্ক্রিয় অবস্থায় প্রতি 5 সেকেন্ডে একবারের বেশি GC হলে — এটি অত্যধিক আবন্টনের লক্ষণ। লেগ করার সময় একটি 㧉িপ ডাম্প নিলে কোন অবজেক্টগুলি মেমরি দখল করছে তা দেখা যায়।
iOS এ, অবজেক্ট তৈরি ও মুক্তি ট্রেক করতে Instruments এ Allocations টেমপ্লেট ব্যবহার করুন। জেনারেশন সক্ষম করুন — এগুলি আপনাকে কাজের মধ্যে 㧉িপ স্ন্যাপশট নিতে ও কোন অবজেক্টগুলি মেমরিতে থাকে তা দেখতে সহায়তা করে। যে স্থায়ী অবজেক্টগুলি মুক্ত হয় না, তারা মেমরি সংচয় ও পরবর্তী বিরতির উৎস।
JankStats একটি Android লাইব্রেরি যা রিয়াল টাইমে হারানো ফ্রেম মীট্রিক্স সংগ্রহ করে। এটি প্রত্যেক jank কে বর্তমান পরিদৃশ্যের (যেমন, “লিস্ট স্ক্রলিং”, “স্ক্রিন খোলা”) সাথে যুক্ত করে, যা দ্বারা কোন নির্দিষ্ট কাজটি লেগ করা ট্রিগার করে তা বোঝা সম্ভব হয়।
Android এ জমা যাওয়া ট্রেকিংয়ের জন্য JankStats সংযুক্তির উদাহরণ:
class MainActivity : AppCompatActivity() {
private lateinit var jankStats: JankStats
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
jankStats = JankStats.create(this.window.decorView) { frameData ->
if (frameData.isJank()) {
Log.w("Jank", "Duration=${frameData.durationMs}ms")
}
}
}
}
লেগ করা দূর করতে প্রতিটি কারণের জন্য নির্দিষ্ট কাজ প্রয়োজন। কোন সার্বজনীন সমাধান নেই — নির্দিষ্ট পরিবেশন প্রোফাইল বিশ্লেষণ প্রয়োজন।
যদি একটি লিস্টে 1000+ আইটেম থাকে ও সকল একসাথে লোড করা হয় — এটি নিশ্চিত লেগ করা। Android এ Paging 3 ও iOS এ NSFetchedResultsController ব্যবহারকারী স্ক্রল করার সাথে ডেটা অংশে লোড করে। ব্যবহারকারী কেবল প্রথম 10–20 আইটেম দেখতে পান; বাকিগুলো পশ্চাত্ ভূমিতে লোড হয়।
Room Android Studio এর ইনস্পেকশন টুলের মাধ্যমে ক্যোরি প্রোফাইলিং করার অনুমতি দেয়: নিষ্পাদন সময়, ফিরিয়ে আনা সারির সংখ্যা ও ক্যোরি পরিকল্পনা দেখা যায়। WHERE ও ORDER BY কলামে ইন্ডেক্স যোগ করা ক্যোরি সময় 300 মিলিসেকেন্ড থেকে 5 মিলিসেকেন্ড কমাতে পারে। iOS এ, Instruments এ Core Data Profiler একটি অনুরূপ পরিক্ষা করে।
পশ্চাত্ ভূমির সিংক, ফাইল ডাউনলোড, ডেটা প্রক্রিয়া — এগুলো WorkManager (Android) বা Background Tasks (iOS) এর মাধ্যমে সম্পাদিত হওয়া উচিত। যদি সিংক রাশি UI থ্রেডে চলে, তবে অ্যাপ নিষ্পাদনের সময় লেগ করবে। WorkManager ব্যাটারি ও নেটওয়ার্ক অবস্থা সম্পর্কে সচেতনতা সহ একটি পশ্চাত্ ভূমির থ্রেডে নিষ্পাদনের গারন্টি দেয়।
Android এ WorkManager এর মাধ্যমে পশ্চাত্ ভূমির সিংকের উদাহরণ:
class SyncWorker(context: Context, params: WorkerParameters)
: CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
return try {
Log.d("সিংক", "পশ্চাত্ ভূমির থ্রেডে ডেটা সিংক করা হচ্ছে")
syncData()
Result.success()
} catch (e: Exception) {
Result.retry()
}
}
}
দক্ষ মেমরি ও থ্রেড পরিচালনার নীতি অনুসরণ করে কোডিং পর্যায়েই লেগ করা প্রতিরোধ করা যাতে পারে।
Baseline Profiles হল ক্লাস ও পদ্ধতির একটি তালিকা যা Android JIT এর পরিবর্তে আগে থেকে (AOT) কম্পাইল করে। প্রোফাইল ছাড়া, প্রতিটি নতুন স্ক্রিন প্রথম বার খোলার সময় কম্পাইল হয়, যা 100–500 মিলিসেকেন্ড বিলম্ব সৃষ্টি করে। মূখ্য স্ক্রিনের জন্য একটি Baseline Profile প্রস্তুত করুন ও baseline-profile-gradle-plugin এর মাধ্যমে Gradle এ জনরেশন সক্ষম করুন।
㦹াট পাথ হল কোড যা প্রতিটি ফ্রেমে নিষ্পাদিত হয়: onBindViewHolder, draw, layoutSubviews। এই পদ্ধতিগুলিতে অবজেক্ট তৈরি করা এড়িয়ে চলুন: অবজেক্ট পূল, কন্কাটেনেশনের পরিবর্তে StringBuilder, ফর্মেটেড স্ট্রিং ও ফর্মেটার ক্যাশ করুন। প্রতিটি অতিরিক্ত আবন্টন পরবর্তী GC কে নিকটবর্তী করে আনে।
আপনার CI পাইপলাইনে লিস্ট স্ক্রলিং ও স্ক্রিন খোলার পরিদৃশ্য সহ Macrobenchmark যোগ করুন। একটি সীমা নির্ধারণ করুন: 99তম পার্সেন্টাইল ফ্রেম সময় 16 মিলিসেকেন্ড অতিক্রম করতে পারবে না। সীমা অতিক্রম হলে — অপ্টিমাইজেশন পর্যন্ত বিল্ড প্রত্যাখ্যান করা হয়।
সাধারণ জিজ্ঞাসা
লেগ হল একটি নিরন্তর বিলম্ব (যেমন, প্রতিটি ট্যাপে 200 মিলিসেকেন্ড). লেগ করা অনিয়মিত: অ্যাপ সাধারণভাবে কাজ করে, তারপর হঠাৎ 1–3 সেকেন্ডের জন্য ধীর হয়ে যায়, তারপর আবার সাধারণ হয়ে যায়। কারণ GC বিরতি বা ডেটাবেস ক্যোরির মতো ইভেন্ট-চালিত কারক।
Android Studio এ Memory Profiler ব্যবহার করুন: Memory ট্যাব GC ইভেন্ট ডেরেশন সহ দেখায়। প্রোডাক্শন মোনিটরিংয়ের জন্য, কাস্টম ট্রেস সহ Firebase Performance Monitoring সংযুক্ত করুন। iOS এ, Malloc Debug সক্ষম করুন ও Instruments এ আবন্টন জেনারেশন চিহ্নিত করুন।
পরোক্ষভাবে — হ্যাঁ। যদি সরভারের প্রতিক্রিয়ায় বিলম্ব হয় ও UI সিংক্রোনাংসভাবে এর জন্য অপেক্ষা করে, তবে অ্যাপ জমে যায়। যদি অনুরোধ অ্যাসিংক্রোনাংস হয় কিন্তু প্রতিক্রিয়া প্রক্রিয়া UI থ্রেডে সম্পাদিত হয় — তাহলেও লেগ করা হবে। সমাধান হল করৌটিন ও অগ্রগতি সূচকের সাথে অ্যাসিংক্রোনাংস প্রক্রিয়া।
ভুল ভাবে ব্যবহার করলে, KMP আংতরিক্রিয়াশীলতার জন্য অতিরিক্ত রেপার অবজেক্ট তৈরি করতে পারে। iOS এ, এটি আবন্টন ফ্রিকোয়েন্সি ও পরিণামস্বরূপ ARC বিরতি বাড়ায়। @ObjCName ব্যবহার করুন, expect/actual অপ্টিমাইজ করুন ও UI 㦹াট পাথ থেকে শেয়ার কোডের বারংবার কল এড়িয়ে চলুন।
android:largeHeap=”true” এর মাধ্যমে 㧉িপ বাড়ালে GC বিলম্বিত হয় কিন্তু আবন্টনের কারণ দূর হয় না। যখন শেষে GC চলে, বিরতিটি আরও দীর্ঘ হবে কারণ আরও অবজেক্ট অতিক্রম করতে হবে। সমাধান 㧉িপ বাড়ানো নয়, আবন্টন সংখ্যা কমানো।
সারাংশ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।