গার্বেজ কালেকশনের মাধ্যমে স্বয়ংক্রিয় মেমরি ব্যবস্থাপনা Android প্ল্যাটফর্মের একটি মূল প্রক্রিয়া, যা ART ভার্চুয়াল মেশিনের উপর ভিত্তি করে তৈরি। Google Android Documentation, 2026 অনুসারে, গার্বেজ কালেক্টর ডেভেলপারকে ম্যানুয়াল মেমরি ব্যবস্থাপনা থেকে মুক্ত করে, স্বয়ংক্রিয়ভাবে সেই অবজেক্টগুলি সরিয়ে দেয় যেগুলোর আর কোনো রেফারেন্স নেই। GC ছাড়া, প্রতিটি অবজেক্ট বরাদ্দের জন্য স্পষ্টভাবে free বা delete কলের প্রয়োজন হতো, যা সেকেন্ডে লক্ষ লক্ষ অবজেক্ট সহ Java ইকোসিস্টেমে শারীরিকভাবে অসম্ভব।
মূল বিষয়
Garbage Collection (GC) হল এমন অবজেক্ট দ্বারা দখলকৃত মেমরি শনাক্ত এবং মুক্ত করার একটি স্বয়ংক্রিয় প্রক্রিয়া যা প্রোগ্রাম আর ব্যবহার করে না। মোবাইল ডেভেলপমেন্টের প্রসঙ্গে, GC Android প্ল্যাটফর্মে ART ভার্চুয়াল মেশিনের মাধ্যমে, সেইসাথে স্ট্যান্ডার্ড Java Virtual Machine-এ ব্যবহৃত হয়।
ম্যানুয়াল মেমরি ব্যবস্থাপনা সহ ভাষার (C, C++) বিপরীতে, যেখানে প্রোগ্রামারকে স্পষ্টভাবে free বা delete কল করতে হয়, GC সম্পূর্ণরূপে অবজেক্ট লাইফসাইকেল ট্র্যাক করার কাজ গ্রহণ করে। ডেভেলপার new অপারেটরের মাধ্যমে নতুন অবজেক্ট তৈরি করে, যখন কালেক্টর নির্ধারণ করে কখন একটি অবজেক্ট অপ্রাপ্য হয়ে যায় — অর্থাৎ এর কাছে আর কোনো সক্রিয় রেফারেন্স নেই।
মূল মেট্রিক GC দক্ষতার হল পজ টাইম (pause time) এবং থ্রুপুট (throughput)। পজ হল সেই সময়কাল যখন সংগ্রহের জন্য অ্যাপ্লিকেশন নির্বাহ বন্ধ থাকে। মোবাইল পরিবেশে, 8–16 মিলিসেকেন্ডের বেশি দীর্ঘ পজ ড্রপ করা ফ্রেম (jank) হিসাবে লক্ষণীয়।
Google I/O 2019 অনুসারে, Android 10-এ ART সাধারণ GC পজ 2–4 ms-এ কমিয়েছে, যা Android 4.4-এ Dalvik-এর তুলনায় 70% কম। তবুও, অনুপযুক্ত মেমরি ব্যবস্থাপনা — লুপে ঘন ঘন অবজেক্ট বরাদ্দ, অপ্রয়োজনীয় অস্থায়ী ইনস্ট্যান্স তৈরি — কর্মক্ষমতা সমস্যার প্রধান কারণ হিসেবে রয়ে গেছে।
Java এবং Android-এ GC-এর সমস্ত বাস্তবায়ন কয়েকটি মৌলিক অ্যালগরিদমের উপর ভিত্তি করে তৈরি যা পজ সময় এবং সংগ্রহের পূর্ণতার মধ্যে ভারসাম্য অর্জনের জন্য একত্রিত হয়। এই অ্যালগরিদমগুলি বোঝা GC-বান্ধব কোড লেখার জন্য অপরিহার্য।
Mark-and-Sweep হল সহজতম অ্যালগরিদম, যা দুটি ধাপে কাজ করে। Mark ধাপে, কালেক্টর রুট রেফারেন্স (root set) — লোকাল ভেরিয়েবল, স্ট্যাটিক ফিল্ড, থ্রেড স্ট্যাক — থেকে শুরু করে অবজেক্ট গ্রাফ ট্রাভার্স করে। প্রতিটি অ্যাক্সেসযোগ্য অবজেক্টকে লাইভ ফ্ল্যাগ দিয়ে চিহ্নিত করা হয়। Sweep ধাপে, কালেক্টর পুরো হিপ স্ক্যান করে এবং চিহ্নিত না হওয়া অবজেক্টের মেমরি মুক্ত করে।
অসুবিধা হল মেমরি খণ্ডিতকরণ: Sweep-এর পরে, মুক্ত এলাকাগুলি দখলকৃত এলাকার সাথে পর্যায়ক্রমে থাকে, যা বড় অবজেক্ট বরাদ্দ করা কঠিন করে তোলে। মোবাইল পরিস্থিতিতে, এটি গুরুত্বপূর্ণ কারণ হিপ সাধারণত ছোট হয় (Android-এ 64–512 MB)।
Copying Collection হিপকে দুটি অর্ধ-স্থানে (semi-spaces) ভাগ করে। সক্রিয় অবজেক্টগুলি ফাঁক ছাড়াই এক অর্ধ-স্থান থেকে অন্যটিতে কমপ্যাক্টভাবে কপি করা হয়। কপি করার পরে, পুরানো অর্ধ-স্থানটি সম্পূর্ণ মুক্ত ঘোষণা করা হয়। অ্যালগরিদম সম্পূর্ণরূপে খণ্ডিতকরণ দূর করে, তবে দ্বিগুণ মেমরি প্রয়োজন।
মোবাইল পরিবেশে, Copying Collection জেনারেশনাল কালেক্টর দ্বারা তরুণ অবজেক্টগুলির দ্রুত পরিষ্কারের জন্য ব্যবহৃত হয়, যা পরিসংখ্যানগতভাবে তাড়াতাড়ি মারা যায় (দুর্বল জেনারেশনাল হাইপোথিসিস)।
Generational Collection হিপকে জেনারেশনে ভাগ করে: Young Generation (তরুণ অবজেক্ট) এবং Old Generation (পুরানো অবজেক্ট যা বেশ কয়েকটি সংগ্রহ থেকে বেঁচে গেছে)। তরুণ জেনারেশনের সংগ্রহ (Minor GC) ঘন ঘন এবং দ্রুত সঞ্চালিত হয়, কারণ বেশিরভাগ অবজেক্ট তরুণ অবস্থায় মারা যায়। পুরানো জেনারেশনের সংগ্রহ (Major GC বা Full GC) কম ঘন ঘন হয় তবে বেশি সময় নেয়।
// জেনারেশনাল GC-র প্রদর্শন: তরুণ অবজেক্ট দ্রুত মারা যায়
void processItems(List<Item> items) {
List<Result> results = new ArrayList<>(); // পুরো মেথড পর্যন্ত বেঁচে থাকে
for (Item item : items) {
Result r = new Result(item.getValue()); // তাৎক্ষণিকভাবে মারা যায়
if (r.isValid()) {
process(r); // r আবর্জনা হয়ে যায়
}
}
saveResults(results); // results Old Gen-এ স্থানান্তরিত হয়
}
এই উদাহরণে, Result অবজেক্টগুলি লুপের ভিতরে তৈরি হয় এবং তৎক্ষণাৎ আবর্জনা হয়ে যায় — এগুলি Young GC-এর জন্য আদর্শ প্রার্থী। results অবজেক্টটি বেশি দিন বেঁচে থাকে এবং Old Generation-এ স্থানান্তরিত হয়। জেনারেশন বিভাজন Minor GC-কে পুরানো হিপ স্পর্শ না করেই মিলিসেকেন্ডে তরুণ অবজেক্ট পরিষ্কার করতে দেয়।
Android Dalvik VM থেকে ART (Android Runtime)-এ বিবর্তিত হয়েছে, এবং GC বাস্তবায়ন তাদের মধ্যে মূল পার্থক্যগুলির মধ্যে একটি। Android-এ GC আর্কিটেকচার বোঝা বাস্তব ডিভাইসে পজ কমানোর কোড লিখতে সাহায্য করে।
| বৈশিষ্ট্য | Dalvik (4.4 পর্যন্ত) | ART (5.0+) |
|---|---|---|
| GC প্রকার | Concurrent Mark সহ Mark-and-Sweep | Generational + Concurrent |
| সাধারণ পজ | 10–30 ms | 2–4 ms |
| কমপ্যাকশন | না (শুধু খণ্ডিতকরণ বাড়ে) | হ্যাঁ (পটভূমিতে, অ্যাপ বন্ধ না করে) |
| AOT কম্পাইলেশন | JIT (Just-In-Time) | AOT + JIT (হাইব্রিড) |
Dalvik একটি সমবর্তী পর্যায়ের সাথে Mark-and-Sweep-এর সংমিশ্রণ ব্যবহার করত। Concurrent Mark অবজেক্ট গ্রাফ ট্রাভার্সালের সময় অ্যাপ্লিকেশনকে কাজ চালিয়ে যেতে দেয়, কিন্তু Sweep ধাপের জন্য সমস্ত থ্রেড বন্ধ করা প্রয়োজন ছিল (Stop-The-World)। RAM কম (512 MB — 1 GB) আছে এমন ডিভাইসে, পজ 30 ms-এ পৌঁছেছিল, যা ইন্টারফেসে লক্ষণীয় ধীরগতি সৃষ্টি করে। এছাড়াও, Dalvik হিপ কমপ্যাক্ট করেনি, তাই দীর্ঘক্ষণ ব্যবহারের পরে খণ্ডিতকরণ বেড়ে যায় এবং বড় অবজেক্ট (যেমন Bitmap) বরাদ্দ করা পর্যাপ্ত মোট মুক্ত মেমরি থাকা সত্ত্বেও OutOfMemoryError দিতে পারে।
ART (Android Runtime) সমবর্তী কমপ্যাকশন সহ একটি জেনারেশনাল কালেক্টর চালু করেছে। হিপ তিনটি অঞ্চলে বিভক্ত: Young, Mature (Old Generation-এর অনুরূপ) এবং Large Object Space (12 KB-এর চেয়ে বড় অবজেক্টের জন্য)। বেশিরভাগ ক্ষেত্রে Young Region সংগ্রহ থ্রেড বন্ধ না করেই সমান্তরালে ঘটে। Android 10+-এ, Concurrent Copying চালু করা হয়েছে — কমপ্যাকশন Stop-The-World ছাড়াই পটভূমি থ্রেডে চলে।
ART-এর আর্কিটেকচারের কারণে, সাধারণ GC পজ 2–4 ms-এ কমেছে, এবং তরুণ অবজেক্টের প্রাধান্যযুক্ত পরিস্থিতিতে — 0.5–1 ms-এ। এটি Android ডিভাইসগুলিকে সক্রিয় মেমরি অপারেশনের সময়ও স্থিতিশীল 60 FPS বজায় রাখতে অনুমতি দিয়েছে।
Java ইকোসিস্টেমে, GC-এর বিভিন্ন বাস্তবায়ন রয়েছে, প্রতিটির নিজস্ব কর্মক্ষমতা প্রোফাইল রয়েছে। Android ডেভেলপমেন্টের জন্য, পছন্দ ART-এর মধ্যে সীমাবদ্ধ, কিন্তু Java GC-এর জ্ঞান মোবাইল অ্যাপ্লিকেশনের জন্য সার্ভার-সাইড কোড লেখার সময় এবং Kotlin Multiplatform-এর সাথে ডেভেলপমেন্টের সময় দরকারী।
Serial GC একটি একক-থ্রেডেড কালেক্টর যার সম্পূর্ণ অ্যাপ্লিকেশন স্টপ (Stop-The-World) রয়েছে। প্রতিটি Mark, Sweep এবং Compact অপারেশন একটি থ্রেড দ্বারা সঞ্চালিত হয়। কর্মক্ষমতা কম — মোবাইল সার্ভারের জন্য ব্যবহৃত হয় না। শুধুমাত্র 100 MB পর্যন্ত হিপ সহ ছোট অ্যাপ্লিকেশনের জন্য উপযুক্ত।
Parallel GC (থ্রুপুট কালেক্টর নামেও পরিচিত) সমস্ত সংগ্রহ ধাপের জন্য একাধিক থ্রেড ব্যবহার করে। এটি সর্বাধিক থ্রুপুট (throughput)-এর দিকে ভিত্তিক — অ্যাপ্লিকেশন রানটাইমের সাপেক্ষে GC-তে ব্যয় করা সময় কমানো। JVM-এ -XX:+UseParallelGC ফ্ল্যাগের মাধ্যমে সক্রিয় করা হয়।
G1 (Garbage-First) GC Java 9+-এ ডিফল্ট কালেক্টর। হিপ 1–32 MB অঞ্চলে বিভক্ত। G1 পজ সময়ের পূর্বাভাস দেয় এবং নির্দিষ্ট সীমার (ডিফল্ট 200 ms) মধ্যে থাকার চেষ্টা করে। অগ্রাধিকার: সবচেয়ে বেশি আবর্জনা আছে এমন অঞ্চলগুলি প্রথমে পরিষ্কার করা হয় (তাই নাম)। G1 পূর্বাভাসযোগ্য পজ সহ বড় হিপযুক্ত সার্ভার (4–64 GB) এর জন্য কার্যকর।
// 100 ms টার্গেট পজ সহ G1 GC সক্ষম করা
// java -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -jar app.jar
public class MemoryMonitor {
private static final long THRESHOLD = 512 * 1024 * 1024; // 512 MB
public void checkHeapUsage() {
Runtime rt = Runtime.getRuntime();
long used = rt.totalMemory() - rt.freeMemory();
if (used > THRESHOLD) {
System.out.println("Heap usage exceeded threshold: " + used);
System.out.println("Consider reducing allocations");
}
}
}
Runtime-এর মাধ্যমে হিপ মনিটরিং প্রাথমিক পর্যায়ে মেমরি লিক সনাক্ত করতে দেয়। যদি স্থিতিশীল অপারেশনে used সর্বোচ্চ হিপের 80% ছাড়িয়ে যায় — এটি সম্ভাব্য লিক বা অ্যাপ্লিকেশন দ্বারা অতিরিক্ত মেমরি খরচের সংকেত।
এমনকি আধুনিক ART GC-ও সমস্ত সমস্যা সমাধান করে না — অনুপযুক্ত মেমরি ব্যবহার jank এবং ANR (Application Not Responding)-এর প্রধান কারণ হিসেবে রয়ে গেছে। আসুন প্রধান পরিস্থিতি এবং অপ্টিমাইজেশন পদ্ধতিগুলি দেখি।
GC Pauses — সংগ্রহের সময় অ্যাপ্লিকেশন থ্রেড বন্ধ হওয়া। পর্দায়, এটি ড্রপ করা ফ্রেম হিসাবে প্রকাশ পায়, যখন দুটি ফ্রেমের মধ্যে সময় 16.6 ms (60 FPS) ছাড়িয়ে যায়। যদি GC 30 ms স্থায়ী হয়, তবে দুটির পরিবর্তে শুধুমাত্র একটি ফ্রেম আঁকা হয় — ব্যবহারকারী ইন্টারফেসে হিচকি দেখেন।
দীর্ঘ পজের প্রধান কারণ: Old Generation-এ বিপুল সংখ্যক জীবিত অবজেক্ট, হিপ খণ্ডিতকরণ, ঘন ঘন Full GC। নির্ণয়ের জন্য Android Studio Profiler এবং systrace ব্যবহার করা হয়।
GC-বান্ধব কোডের প্রধান নিয়ম হল বরাদ্দকৃত অবজেক্টের সংখ্যা কমানো। প্রতিটি নতুন অবজেক্টের জন্য শুধুমাত্র মেমরি বরাদ্দ নয়, পরবর্তী সংগ্রহেরও প্রয়োজন হয়। এমনকি যদি GC দ্রুত হয়, প্রতি সেকেন্ডে 1000 অতিরিক্ত বরাদ্দ কালেক্টরের জন্য 1000 চেক তৈরি করে।
মেমরি লিক ঘটে যখন একটি অবজেক্ট অ্যাক্সেসযোগ্য থাকে যদিও এর আর প্রয়োজন নেই। GC এই ধরনের অবজেক্ট মুছে ফেলতে পারে না এবং মেমরি ধীরে ধীরে শেষ হয়ে যায়। সাধারণ কারণ: নিবন্ধিত না হওয়া শ্রোতা, Activity-র স্ট্যাটিক রেফারেন্স, বাহ্যিক প্রসঙ্গ ক্যাপচার করা বেনামী ক্লাস এবং বন্ধ না করা Cursor/InputStream।
// মেমরি লিক: বেনামী ক্লাস Activity-র রেফারেন্স ধরে রাখে
public void startTask() {
new Thread(new Runnable() { // অন্তর্নিহিতভাবে this (Activity) ধরে রাখে
@Override
public void run() {
// দীর্ঘ অপারেশন...
System.out.println("Done");
}
}).start();
}
// সমাধান: স্ট্যাটিক নেস্টেড ক্লাস + WeakReference
private static class TaskRunnable implements Runnable {
private WeakReference<Activity> activityRef;
TaskRunnable(Activity activity) {
this.activityRef = new WeakReference<>(activity);
}
@Override
public void run() {
Activity act = activityRef.get();
if (act != null) {
// Activity-র সাথে নিরাপদ কাজ
}
}
}
এই উদাহরণে, বেনামী Runnable Activity-র একটি অন্তর্নিহিত রেফারেন্স ক্যাপচার করে। যতক্ষণ থ্রেডটি জীবিত থাকে — ব্যবহারকারী স্ক্রিন বন্ধ করে দিলেও Activity GC দ্বারা সংগ্রহ করা যায় না। WeakReference + স্ট্যাটিক ক্লাস সংশোধন এই শৃঙ্খল ভেঙ্গে দেয় এবং Activity-কে মুক্ত করার অনুমতি দেয়।
সচরাচর জিজ্ঞাসিত প্রশ্ন
Android (ART)-এ GC হল সমবর্তী কমপ্যাকশন সহ একটি জেনারেশনাল কালেক্টর, যা সীমিত মেমরি সহ মোবাইল ডিভাইসের জন্য অপ্টিমাইজ করা। Java GC (G1, ZGC) হল বড় হিপ এবং পূর্বাভাসযোগ্য পজ সহ সার্ভার-সাইড কালেক্টর। ART GC JVM ফ্ল্যাগ ব্যবহার করে না — সমস্ত টিউনিং OS স্তরে স্বয়ংক্রিয়ভাবে সম্পন্ন হয়।
Stop-The-World হল সেই মুহূর্ত যখন কালেক্টর অবজেক্ট গ্রাফ নিরাপদে ট্রাভার্স করতে বা মেমরি মুক্ত করতে অ্যাপ্লিকেশনের সমস্ত থ্রেড বিরাম দেয়। STW যত দীর্ঘ, jank তত বেশি লক্ষণীয়। ART তার জেনারেশনাল আর্কিটেকচারের কারণে সাধারণ STW সময় 2–4 ms-এ কমিয়েছে।
Android Studio Memory Profiler ব্যবহার করুন — এটি হিপ বৃদ্ধি, বরাদ্দের সংখ্যা দেখায় এবং Heap Dump নেওয়ার অনুমতি দেয়। গভীর বিশ্লেষণের জন্য, LeakCanary ব্যবহার করুন — লাইব্রেরি স্বয়ংক্রিয়ভাবে লিক সনাক্ত করে এবং GC সংগ্রহ প্রতিরোধকারী রেফারেন্স চেইন দেখায়।
Full GC হল Old Generation সহ সমস্ত হিপ জেনারেশনের সম্পূর্ণ সংগ্রহ। মোবাইল অ্যাপ্লিকেশনে, Full GC 50–200 ms স্থায়ী হতে পারে, যা লক্ষণীয় jank বা ANR সৃষ্টি করে। প্রধান কারণ: হিপ খণ্ডিতকরণ, মেমরি লিক, Old Generation সীমা অতিক্রম করা।
Kotlin স্ট্রাকচার্ড কনকারেন্সি সহ coroutine প্রদান করে — স্কোপ বাতিলকরণ স্বয়ংক্রিয়ভাবে সমস্ত চাইল্ড coroutine বাতিল করে, লিক প্রতিরোধ করে। Kotlin-এ বিলম্বিত আরম্ভের জন্য lazy ডেলিগেট এবং স্কোপ ফাংশনও রয়েছে যা অস্থায়ী অবজেক্টের সংখ্যা কমায়।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন