মেমোরি লিক ও ব্লোট — এটি কী, কারণ এবং কীভাবে এড়াবেন

লেখক: IT Sectr প্রকাশিত: 2026-07-28 পড়ার সময়: 10 মিনিট

মেমোরি লিক — মোবাইল ডেভেলপমেন্টের সবচেয়ে কপট সমস্যাগুলোর একটি। অ্যাপের মেমোরি ব্যবহার ক্রমাগত বাড়তে থাকে যতক্ষণ না এটি OS দ্বারা নির্ধারিত সীমায় পৌঁছায়, তারপরে OutOfMemoryError বা জোর করে বন্ধ হয়ে যায়। Square Engineering-এর মতে, প্রায় 40% Android অ্যাপে কমপক্ষে একটি মেমোরি লিক থাকে যা শুধুমাত্র প্রোফাইলিংয়ের মাধ্যমে সনাক্ত করা যায়। আসুন কারণ এবং মেমোরি বৃদ্ধি রোধের পদ্ধতিগুলো পর্যালোচনা করি।

মূল বিষয়

  • GC পৌঁছানোর ক্ষমতা — রুট সেট থেকে সক্রিয় রেফারেন্স থাকলে অবজেক্ট মুছে ফেলা হয় না
  • Activity বা Context-এর স্ট্যাটিক রেফারেন্স — Android-ে লিকের সবচেয়ে সাধারণ কারণ
  • LeakCanary — Android-ে স্বয়ংক্রিয় লিক সনাক্তকরণের জন্য মানক টুল
  • WeakReference — সেই রেফারেন্সগুলোর সমাধান যা গার্বেজ কালেকশনে বাধা দেওয়া উচিত নয়
  • Lifecycle-aware উপাদান ভিউ ধ্বংস হলে স্বয়ংক্রিয়ভাবে সাবস্ক্রিপশন বাতিল করে

মেমোরি লিক ও অ্যাপ ব্লোট কী?

মেমোরি লিক — এমন একটি অবস্থা যেখানে একটি অবজেক্ট যা আর অ্যাপের প্রয়োজন নেই, হিপে ধরে রাখা হয় কারণ GC রুট সেট থেকে একটি সক্রিয় রেফারেন্স এখনও তার দিকে নির্দেশ করছে। গার্বেজ কালেক্টর এই ধরনের অবজেক্টকে জীবিত মনে করে এবং তা সরায় না।

মেমোরি ব্লোট — একটি বিস্তৃত সমস্যা যেখানে অ্যাপ তার বর্তমান কাজগুলো সম্পাদনের জন্য প্রয়োজনীয়তার চেয়ে বেশি মেমোরি ব্যবহার করে। কারণ: অতিরিক্ত ক্যাশিং, অবজেক্ট ডুপ্লিকেশন, অনুপযুক্ত ডেটা স্ট্রাকচার এবং হিপ ফ্র্যাগমেন্টেশন।

Android-এ, প্রতিটি অ্যাপের জন্য সীমিত হিপ বরাদ্দ করা হয় (সাধারণত ডিভাইস এবং OS সংস্করণের উপর নির্ভর করে 64–512 MB)। iOS-এ, সীমা কম কঠোর, কিন্তু সীমার কাছাকাছি পৌঁছালে সিস্টেম একটি মেমোরি সতর্কতা পাঠায়।

বৈশিষ্ট্যAndroidiOS
হিপ সীমা64–512 MB (ডিভাইসের উপর নির্ভরশীল)অন্তর্নিহিত (সিস্টেম)
গার্বেজ কালেকশনART (সমবর্তী, কমপ্যাক্ট)ARC (স্বয়ংক্রিয় রেফারেন্স কাউন্টিং)
লিক প্রক্রিয়াGC রুট রেফারেন্সরিটেইন চক্র (শক্তিশালী রেফারেন্স চক্র)
ফলাফলOutOfMemoryErrorমেমোরি সতর্কতা → সমাপ্তি

Facebook Engineering Blog-এর মতে, মেমোরি লিক মোবাইল অ্যাপে ~15% ক্র্যাশ রিপোর্টের কারণ। Android-এ, মেমোরি কম থাকলে ঘন ঘন GC বিরতির কারণে ANR যুক্ত হয়।

Android ও iOS-এ সাধারণ মেমোরি লিক প্যাটার্ন

Activity-তে স্ট্যাটিক রেফারেন্স — একটি ক্লাসিক Android লিক। যদি একটি স্ট্যাটিক ফিল্ড বা সিঙ্গেলটন Activity-র রেফারেন্স রাখে, তবে finish()-এর পরেও GC এটি সংগ্রহ করবে না যতক্ষণ সিঙ্গেলটন জীবিত থাকে। Activity একটি ভারী অবজেক্ট যাতে ভিউ হায়ারার্কি, রিসোর্স এবং Context থাকে।

kotlin
object LeakHolder {
    var activityRef: Activity ?= null // leak: static reference to Activity
}

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle ?= null) {
        super.onCreate(savedInstanceState)
        LeakHolder.activityRef = this // ❌ MainActivity will never be GC'd
    }
}

বেনামী ক্লাস ও ল্যাম্বডা — বাইরের ক্লাসের একটি রেফারেন্স অন্তর্নিহিতভাবে ধরে রাখে। যদি Runnable বা Callback একটি বাহ্যিক সার্ভিসে পাঠানো হয় এবং Activity ধ্বংস হয়ে যায়, তবে বেনামী ক্লাসের অবজেক্টটি এখনও কিউতে থাকে এবং Activity-কে গার্বেজ কালেক্ট হতে বাধা দেয়।

  • Handler বিলম্বসহ — Activity ধ্বংস হলে কিন্তু Handler.postDelayed এখনও কার্যকর না হলে, Activity লিক হয়
  • Thread ও AsyncTask — স্ক্রিন ঘোরালে, Activity পুনরায় তৈরি হয় যখন পুরনো Thread পুরনো Activity-র রেফারেন্স ধরে রাখে
  • Retrofit/Callback — একটি বেনামী Callback প্রেজেন্টার বা ফ্র্যাগমেন্টের রেফারেন্স রাখে
  • পর্যবেক্ষক — onDestroy-এ আনসাবস্ক্রাইব না করেই LiveData বা RxJava সাবস্ক্রিপশন

iOS-এ, প্রধান সমস্যা হল রিটেইন চক্র: দুটি অবজেক্ট একে অপরের শক্তিশালী রেফারেন্স রাখে এবং ARC কারও জন্য রেফারেন্স গণনা শূন্য করতে পারে না। একটি সাধারণ উদাহরণ: একটি ক্লোজার যা self-কে শক্তভাবে ক্যাপচার করে, এবং self যা ক্লোজারের রেফারেন্স রাখে।

কীভাবে মেমোরি লিক সনাক্ত করবেন?

LeakCanary — Android-এ স্বয়ংক্রিয় লিক সনাক্তকরণের জন্য Square-এর একটি লাইব্রেরি। Activity বা Fragment ধ্বংস হওয়ার পরে, এটি পরীক্ষা করে যে অবজেক্টটি GC দ্বারা সংগ্রহ করা হয়েছে কিনা। না হলে, এটি হিপ ডাম্প নেয় এবং লিক ট্রেস দেখায়।

kotlin
// LeakCanary 2.x — auto-integration via Application
class ExampleApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // LeakCanary auto-installs in debug build
        // via ContentProvider — zero code setup
    }
}

// Force check invocation
AppWatcher.objectWatcher.watch(watchedObject, "leak description")

Android Studio Profiler — রিয়েল-টাইম মেমোরি মনিটরিংয়ের জন্য একটি অন্তর্নির্মিত টুল। এটি হিপ ডাম্প রেকর্ড করতে, সন্দেহজনক অবজেক্ট (Retained Size > 1 MB) খুঁজতে এবং প্রতিটি অবজেক্টে GC রুট পাথ ট্রেস করতে দেয়।

iOS-এর জন্য, Xcode Memory Graph Debugger ব্যবহার করুন। এটি মেমোরিতে অবজেক্ট গ্রাফ ভিজ্যুয়ালাইজ করে, রিটেইন চক্র দেখায় এবং তাৎক্ষণিকভাবে বৃত্তাকার রেফারেন্স সনাক্ত করতে দেয়। দীর্ঘমেয়াদী মনিটরিংয়ের জন্য Instruments > Allocations-ও উপলব্ধ।

প্রতিরোধ কৌশল

WeakReference — সেই রেফারেন্সগুলোর জন্য একটি মৌলিক প্রক্রিয়া যা গার্বেজ কালেকশনে বাধা দেওয়া উচিত নয়। যদি GC কোনো অবজেক্ট সংগ্রহ করার সিদ্ধান্ত নেয়, WeakReference null ফেরত দেয়। এটি কলব্যাক, শ্রোতা এবং ব্যাকগ্রাউন্ড থ্রেড থেকে UI উপাদানের রেফারেন্সের জন্য ব্যবহৃত হয়।

Lifecycle-aware উপাদান — Android Jetpack (Lifecycle, LiveData, Flow, coroutines)-এ বাস্তবায়িত একটি আর্কিটেকচারাল পদ্ধতি। onDestroy-এ সাবস্ক্রিপশন স্বয়ংক্রিয়ভাবে বাতিল হয়, যা লিকের প্রধান শ্রেণীকে দূর করে।

kotlin
class MyViewModel : ViewModel() {
    private val _data = MutableLiveData<List<User>>()
    val data: LiveData<List<User>> get() = _data

    fun loadData() {
        viewModelScope.launch {
            val result = repository.fetchData()
            _data.postValue(result)
            // coroutine auto-cancels on onCleared()
        }
    }
}

viewModelScopelifecycleScope — Android-এ অন্তর্নির্মিত CoroutineScope যা সংশ্লিষ্ট জীবনচক্র ইভেন্টে বাতিল হয়। এটি coroutine-এর মাধ্যমে লিক দূর করে — আধুনিক Android ডেভেলপমেন্টের সবচেয়ে সাধারণ পরিস্থিতি।

  • ব্যবহার করবেন না Context, Activity, View বা Fragment-এর স্ট্যাটিক রেফারেন্স
  • বাতিল করুন onDestroy-এ disposeBag / CompositeDisposable-এ সমস্ত RxJava সাবস্ক্রিপশন
  • ব্যবহার করুন iOS ক্লোজারে [weak self] / [unowned self] রিটেইন চক্র প্রতিরোধ করতে
  • পরীক্ষা করুন Bitmap ও বড় অবজেক্ট — সেগুলো রিসাইকেল বা নাল করা উচিত

মেমোরি প্রোফাইলিং টুল

Android Studio-তে Memory Profiler — হিপ মনিটরিংয়ের জন্য প্রাথমিক টুল। এটি লাইভ অ্যালোকেশন, হিপ স্ন্যাপশট এবং ধরন অনুসারে অবজেক্ট গণনা দেখায়। এটি একটি ডাম্প রেকর্ড করতে এবং সন্দেহজনক অবজেক্ট খুঁজতে MAT (Memory Analyzer Tool)-এ বিশ্লেষণ করতে দেয়।

Eclipse MAT — একটি ডেস্কটপ হিপ ডাম্প বিশ্লেষক। Android Studio থেকে HPROF ফাইল লোড করার পর, MAT একটি ডমিনেটর ট্রি তৈরি করে, প্রতিটি অবজেক্টের রিটেইন সাইজ দেখায় এবং Leak Suspects Report-এর মাধ্যমে স্বয়ংক্রিয় লিক সন্দেহভাজন বিশ্লেষণ প্রদান করে।

Xcode Memory Graph — একটি ভিজ্যুয়াল রিটেইন চক্র ডিবাগার। Memory Graph Debugger বাটনে ক্লিক করলে, Xcode অ্যাপ বন্ধ করে, মেমোরিতে একটি সম্পূর্ণ অবজেক্ট গ্রাফ তৈরি করে এবং রিটেইন চক্র লাল রঙে হাইলাইট করে।

টুলপ্ল্যাটফর্মবৈশিষ্ট্য
LeakCanaryAndroidধ্বংসের পর লিকের স্বয়ংক্রিয় সনাক্তকরণ
Memory ProfilerAndroid Studioহিপ ডাম্প + লাইভ অ্যালোকেশন
Eclipse MATAndroidডমিনেটর ট্রি, Leak Suspects Report
Memory GraphiOS (Xcode)রিটেইন চক্র ভিজ্যুয়ালাইজার

Google I/O 2023-এর মতে, ডিবাগ বিল্ডে LeakCanary ব্যবহারকারী অ্যাপগুলি গ্রহণের প্রথম 2 মাসে মেমোরি-সম্পর্কিত ক্র্যাশ 30–50% কমায়। প্রকল্প অনবোর্ডিং পর্যায়ে LeakCanary যোগ করার পরামর্শ দেওয়া হয়।

সচরাচর জিজ্ঞাসা

মেমোরি লিক ব্লোট থেকে কীভাবে আলাদা?

লিক — অবজেক্ট যা কোডের জন্য অ্যাক্সেসযোগ্য নয় কিন্তু সক্রিয় রেফারেন্সের কারণে GC দ্বারা সংগ্রহ করা হয় না। ব্লোট — অ্যাপ এমন অবজেক্ট ধরে রাখে যা যৌক্তিকভাবে প্রয়োজন কিন্তু অতিরিক্ত পরিমাণে (যেমন, 80 MB চলমান অ্যাপে 50 MB ক্যাশ)। ব্লোট স্থাপত্যিকভাবে ঠিক করা হয়; লিক — সঠিক রেফারেন্স ব্যবস্থাপনার মাধ্যমে।

LeakCanary কীভাবে লিক খুঁজে পায়?

LeakCanary ObjectWatcher ব্যবহার করে — Activity-র onDestroy()-এর পর, এটি Activity-তে একটি WeakReference তৈরি করে এবং GC চালায়। যদি 5 সেকেন্ড পর WeakReference সাফ না হয়, LeakCanary হিপ ডাম্প নেয়, GC Root থেকে অবজেক্ট পর্যন্ত সবচেয়ে ছোট রেফারেন্স চেইন বিশ্লেষণ করে এবং ফাইল ও কোড লাইনসহ সঠিক লিক স্ট্যাক দেখায়।

Bitmap কেন প্রায়ই OutOfMemoryError ঘটায়?

Bitmap জাভা হিপের বাইরে নেটিভ মেমোরিতে (নেটিভ হিপ) মেমোরি দখল করে। একটি Bitmap-এর আকার = প্রস্থ × উচ্চতা × 4 বাইট (ARGB_8888)। একটি 12 MP ছবি (4000×3000) 48 MB নেয়। Android সবসময় সময়মতো নেটিভ মেমোরি মুক্ত করতে পারে না, তাই একাধিক Bitmap জমে পর্যাপ্ত Java হিপ থাকলেও OOM হয়।

iOS-এ রিটেইন চক্র কী?

রিটেইন চক্র — ARC-তে এমন একটি অবস্থা যেখানে দুটি অবজেক্ট একে অপরের শক্তিশালী রেফারেন্স রাখে এবং রেফারেন্স গণনা কখনই শূন্যে পৌঁছায় না। একটি সাধারণ উদাহরণ: একটি ViewController যার ক্লোজারে শক্তিশালী রেফারেন্স আছে এবং ক্লোজার self-কে শক্তভাবে ক্যাপচার করে। সমাধান: ক্লোজারে [weak self] বা [unowned self] ব্যবহার করুন।

Android-এ সর্বোচ্চ হিপ আকার কত?

হিপ-এর আকার ডিভাইস এবং Android সংস্করণের উপর নির্ভর করে। পুরনো ডিভাইসের জন্য (API 15–24) — 64–128 MB। আধুনিকগুলোর জন্য (API 25+) — 256–512 MB। সঠিক মান ActivityManager.getMemoryClass()-এর মাধ্যমে পাওয়া যায়। বড় অ্যাপের (গেম, এডিটর) জন্য, ম্যানিফেস্টে largeHeap=true 1 GB পর্যন্ত প্রদান করে।

সারসংক্ষেপ

  • মেমোরি লিক — রুট সেট থেকে সক্রিয় রেফারেন্সের কারণে GC-র দ্বারা সংগৃহীত না হওয়া অবজেক্ট; ব্লোট — স্পষ্ট লিক ছাড়াই অতিরিক্ত মেমোরি খরচ
  • Activity, Context বা View-এর স্ট্যাটিক রেফারেন্স — Android-এ লিকের এক নম্বর কারণ; সমাধান — WeakReference বা Application Context
  • বেনামী ক্লাস ও ল্যাম্বডা বাইরের ক্লাসের অন্তর্নিহিত রেফারেন্স ধরে রাখে; বাতিল না করা কলব্যাক দ্বিতীয় সবচেয়ে সাধারণ কারণ
  • LeakCanary — Android-এ লিকের স্বয়ংক্রিয় সনাক্তকরণের মানক; সংহতকরণে 5 মিনিট সময় লাগে এবং ক্র্যাশ রেট 30–50% কমায়
  • lifecycleScopeviewModelScope ধ্বংসে স্বয়ংক্রিয়ভাবে coroutine বাতিল করে, লিকের পুরো একটি শ্রেণী দূর করে
  • iOS-এ রিটেইন চক্র ক্লোজার ও ডেলিগেটে weak/unowned self দিয়ে সমাধান করা হয়
  • মেমোরি প্রোফাইল করুন প্রতি স্প্রিন্টে অন্তত একবার — MAT বা Memory Graph-এর সাথে হিপ ডাম্প কোড রিভিউর অংশ হওয়া উচিত

আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব

IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।

প্রকল্প নিয়ে আলোচনা করুন

আরও পড়ুন