WebView মেমরি পরিচালনা এবং নির্ণয় করুন

আপনার অ্যান্ড্রয়েড অ্যাপে ওয়েব কন্টেন্ট রেন্ডার করার জন্য WebView একাধিক প্রসেস জুড়ে নেটিভ কোড চালায়। WebView ইনস্ট্যান্সগুলোকে অব্যবস্থাপিত রাখলে মেমরি লিক, আউট-অফ-মেমরি (OOM) ক্র্যাশ এবং অ্যাপের পারফরম্যান্স হ্রাস পেতে পারে।

এই ডকুমেন্টটি WebView মাল্টি-প্রসেস মেমরি মডেল ব্যাখ্যা করে, মেমরি লিক প্রতিরোধ করার জন্য এর লাইফসাইকেল কীভাবে সঠিকভাবে পরিচালনা করতে হয় তা বর্ণনা করে এবং মেমরি সংক্রান্ত সমস্যা নির্ণয়ের জন্য ব্যবহারিক ওয়ার্কফ্লো প্রদান করে।

WebView মেমরি আর্কিটেকচার বুঝুন

WebView মেমরি কার্যকরভাবে পরিচালনা করতে, অ্যান্ড্রয়েড কীভাবে ওয়েব কন্টেন্টের জন্য রিসোর্স বরাদ্দ করে তা বুঝুন:

  • মাল্টি-প্রসেস এক্সিকিউশন: অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং এর পরবর্তী সংস্করণগুলোতে, WebView আপনার অ্যাপের মূল ফাংশনগুলো থেকে ওয়েব কন্টেন্টকে একাধিক প্রসেসে আলাদা করে রাখে (কম র‍্যামের ডিভাইসে এটি একটিমাত্র প্রসেসে ফিরে যেতে পারে):

    • হোস্ট (ব্রাউজার) প্রসেস: অ্যাপের প্রধান প্রসেস, যেখানে আপনার Activity এবং জাভা বা কোটলিন কোড চলে।
    • বিচ্ছিন্ন রেন্ডারার প্রসেস: একটি পৃথক স্যান্ডবক্সড প্রসেস ( SandboxedProcessService ) যা HTML ও CSS পার্স করে, জাভাস্ক্রিপ্ট এক্সিকিউট করে এবং ওয়েব পেজ রেন্ডার করে।
  • নেটিভ মেমরি ফুটপ্রিন্ট: WebView বেশিরভাগ মেমরি—রেন্ডার করা গ্রাফিক্স, DOM ট্রি এবং জাভাস্ক্রিপ্ট রানটাইম মেমরি সহ—জাভা হিপে নয়, বরং নেটিভ মেমরিতে বরাদ্দ করা হয়। একটি জাভা হিপ ডাম্প ( .hprof ) শুধুমাত্র একটি লাইটওয়েট জাভা র‍্যাপার অবজেক্ট দেখায় এবং ওয়েব কন্টেন্ট দ্বারা ব্যবহৃত প্রকৃত মেমরি ধারণ করে না।

  • নেটিভ মেমরির সিস্টেমগত ​​প্রভাব: জাভা হিপ অ্যালোকেশনের মতো নয়, যা অ্যাপের maxHeap লিমিট দ্বারা সীমাবদ্ধ থাকে এবং OutOfMemoryError দেখিয়ে দ্রুত ব্যর্থ হয়, নেটিভ মেমরি নীরবে গিগাবাইট পর্যন্ত বাড়তে পারে। যখন অব্যবহৃত নেটিভ মেমরি ফিজিক্যাল র‍্যাম এবং সোয়াপ স্পেস (zRAM) পূর্ণ করে ফেলে, তখন অ্যান্ড্রয়েডের লো মেমরি কিলার (LMK) মেমরি পুনরুদ্ধারের জন্য ব্যাকগ্রাউন্ড প্রসেসগুলো বন্ধ করতে শুরু করে। এটি ফোরগ্রাউন্ড অ্যাপটিকে পুরোপুরি বন্ধ করে দেওয়ার আগে ডিভাইসের সার্বিক মাল্টিটাস্কিংয়ের মান কমিয়ে দেয়।

WebView-এর জীবনচক্র পরিচালনা করুন

মেমরি লিক প্রতিরোধের জন্য সঠিক লাইফসাইকেল ম্যানেজমেন্ট অত্যন্ত গুরুত্বপূর্ণ। একটি সাধারণ ভুল ধারণা হলো যে, আপনার লেআউট থেকে একটি WebView সরিয়ে ফেললে বা একটি Activity শেষ হতে দিলে তার মেমরি স্বয়ংক্রিয়ভাবে মুক্ত হয়ে যায়।

WebView ইনস্ট্যান্সগুলি পরিষ্কার করুন

আপনার Activity বা Fragment ধ্বংস হয়ে গেলে একটি সুষ্ঠু শাটডাউন নিশ্চিত করতে এবং রিসোর্স মুক্ত করতে:

  1. WebView টিকে তার প্যারেন্ট কন্টেইনার ( ViewGroup ) থেকে সরিয়ে ফেলুন।
  2. সক্রিয় লোডিং বন্ধ করুন এবং নেভিগেশন ইতিহাস মুছে ফেলুন।
  3. destroy() কল করুন।
  4. null এর উল্লেখটি মুছে ফেলুন।

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি WebView সঠিকভাবে পরিষ্কার করতে হয়:

কোটলিন

override fun onDestroy() {
    myWebView?.let {
        // Remove the WebView from its parent ViewGroup.
        (it.parent as? ViewGroup)?.removeView(it)
        // Stop active loading and clear history.
        it.stopLoading()
        it.clearHistory()
        // Destroy the instance.
        it.destroy()
    }
    myWebView = null
    super.onDestroy()
}

জাভা

@Override
protected void onDestroy() {
    if (myWebView != null) {
        // Remove the WebView from its parent ViewGroup.
        if (myWebView.getParent() instanceof ViewGroup) {
            ((ViewGroup) myWebView.getParent()).removeView(myWebView);
        }
        // Stop active loading and clear history.
        myWebView.stopLoading();
        myWebView.clearHistory();
        // Destroy the instance.
        myWebView.destroy();
    }
    myWebView = null;
    super.onDestroy();
}

ধ্বংস-পরবর্তী স্মৃতি বুঝুন

যখন আপনি destroy() কল করেন, তখন সিস্টেম Activity কনটেক্সট মুক্ত করে, ভিউ হায়ারার্কিগুলো পরিষ্কার করে এবং ওয়েব ব্যাকগ্রাউন্ডের কাজ বন্ধ করে দেয়। তবে, আপনি লক্ষ্য করতে পারেন যে প্রসেসটির ফিজিক্যাল মেমরি (রেসিডেন্ট সেট সাইজ) সঙ্গে সঙ্গে তার WebView-পূর্ববর্তী বেসলাইনে নেমে আসে না।

এই আচরণটি স্বাভাবিক। নেটিভ রানটাইম ক্যাশ, শেয়ার্ড লাইব্রেরি এবং বরাদ্দকৃত মেমরি পেজগুলো প্রসেসের মধ্যেই থেকে যায়, যতক্ষণ না অপারেটিং সিস্টেম সেগুলোকে পুনরুদ্ধার করে অথবা প্রসেসটি বন্ধ হয়ে যায়। destroy() ফাংশনের প্রধান উদ্দেশ্য হলো, ব্যবহারকারীরা যখন ওয়েব-চালিত স্ক্রিনগুলোতে প্রবেশ করে ও বের হয়, তখন Activity ক্রমবর্ধমান মেমরি লিক প্রতিরোধ করা।

মূল ডিবাগিং মেট্রিক্স

WebView মেমরি ব্যবহার বিশ্লেষণ করার সময়, নিম্নলিখিত মেট্রিকগুলোর উপর মনোযোগ দিন:

  • রেসিডেন্ট সেট সাইজ (RSS): প্রসেসটিতে ম্যাপ করা মোট ফিজিক্যাল র‍্যাম, যার মধ্যে শেয়ার্ড কোড এবং লাইব্রেরি অন্তর্ভুক্ত থাকে (অ্যান্ড্রয়েড স্টুডিও প্রোফাইলার-এ এটিকে 'Total' হিসেবে চিহ্নিত করা হয়)।

  • অ্যানোনিমাস আরএসএস (RssAnon): প্রসেস দ্বারা সরাসরি বরাদ্দকৃত মেমরি, যা ডিস্কের কোনো ফাইল দ্বারা সমর্থিত নয় (যেমন নেটিভ হিপ এবং জাভাস্ক্রিপ্ট রানটাইম অ্যালোকেশন)। এটি আপনার ওয়েব কন্টেন্টের প্রধান মেমরি খরচকে নির্দেশ করে (অ্যান্ড্রয়েড স্টুডিও প্রোফাইলার-এ এটিকে 'Allocated' হিসেবে চিহ্নিত করা হয়)।

  • প্রাইভেট মেমোরি ফুটপ্রিন্ট (PMF): অ্যানোনিমাস RSS এবং সোয়াপ (zRAM)-এর সমষ্টি। PMF আপনার অ্যাপ দ্বারা সিস্টেমের উপর আরোপিত প্রকৃত ও অপসারণ-অযোগ্য মেমোরির বোঝা প্রতিফলিত করে।

  • ব্রাউজার পিএমএফ বনাম রেন্ডারার পিএমএফ: আপনার অ্যাপের প্রধান প্রসেস দ্বারা ব্যবহৃত মেমরি বনাম বিচ্ছিন্ন রেন্ডারার প্রসেস দ্বারা ব্যবহৃত মেমরি। ভারী ওয়েব কন্টেন্টের কারণে প্রধানত রেন্ডারার প্রসেসেই মেমরি ব্যবহারের আকস্মিক বৃদ্ধি ঘটে।

  • লাইভ অবজেক্ট কাউন্ট ( WebViews , Activities , Views ): মেমরিতে থাকা সক্রিয় UI, কনটেক্সট এবং WebView ইনস্ট্যান্সের সংখ্যা। এগুলি ট্র্যাক করার মাধ্যমে শনাক্ত করা যায় যে, মেমরির এই বৃদ্ধি রিটেইনড জাভা রেফারেন্সের কারণে হচ্ছে, নাকি শুধুমাত্র নেটিভ অ্যালোকেশনের কারণে।

  • প্রাইভেট আদার এবং নেটিভ হিপ: dumpsys meminfo তে, নেটিভ C/C++ অ্যালোকেশন এবং কাস্টম মেমরি ম্যাপিং (যেমন Chromium PartitionAlloc বা এমবেডেড জাভাস্ক্রিপ্ট রানটাইম হিপ) Java Heap-এর পরিবর্তে Native Heap এবং Private Other-এর অধীনে প্রদর্শিত হয়।

প্রসেস মেমরি কাউন্টার এবং তাদের শ্রেণীবিভাগ সম্পর্কে আরও তথ্যের জন্য, প্রসেস মেমরি শব্দকোষ দেখুন।

ব্যবহারিক রোগনির্ণয় কর্মপ্রবাহ

যেহেতু WebView একাধিক প্রসেস জুড়ে কাজ করে এবং নিজস্ব মেমরি বরাদ্দ করে, তাই এর ফুটপ্রিন্ট পরীক্ষা করার জন্য নিম্নলিখিত টুল এবং কৌশলগুলো ব্যবহার করুন:

প্রোফাইলিং এবং ডায়াগনস্টিক সরঞ্জাম

মেমরি অ্যালোকেশন পরিদর্শন করতে এবং মেমরি লিক নির্ণয় করতে নিম্নলিখিত টুলগুলি ব্যবহার করুন:

  • অ্যান্ড্রয়েড স্টুডিও মেমরি প্রোফাইলার: নেটিভ অ্যালোকেশনগুলো দেখতে, সময়ের সাথে সাথে মেমরির বিভিন্ন ক্যাটাগরি ট্র্যাক করতে এবং স্ক্রিন পরিবর্তনের সময় Activity মেমরি লিক শনাক্ত করতে মেমরি প্রোফাইলার ব্যবহার করুন।

  • পারফেট্টো দিয়ে মেমরি ট্র্যাকিং: সামগ্রিক মেমরি বৃদ্ধি পর্যবেক্ষণ করতে পারফেট্টো ব্যবহার করে সিস্টেম-স্তরের মেমরি কাউন্টার (যেমন RSS এবং Anonymous RSS) রেকর্ড করুন। মনে রাখবেন যে WebView নেটিভ ইঞ্জিন অ্যালোকেশন পারফেট্টোর হিপ প্রোফাইলিং টুলে কলস্ট্যাক তৈরি করে না। ওয়েব কন্টেন্টের ভেতরের জাভাস্ক্রিপ্ট হিপ স্ন্যাপশট এবং DOM অ্যালোকেশন পরীক্ষা করতে Chrome DevTools ব্যবহার করুন।

লাইভ অবজেক্ট সংখ্যা পরিদর্শন করুন

মেমোরি বৃদ্ধি অবশিষ্ট জাভা র‍্যাপার বা নেটিভ অ্যালোকেশনের কারণে হচ্ছে কিনা তা নির্ধারণ করতে, dumpsys meminfo এর Objects অংশটি পরীক্ষা করুন:

adb shell dumpsys meminfo -a <var>PACKAGE_NAME</var> | grep -A 10 "Objects"

আউটপুটটি লাইভ অবজেক্ট সংখ্যা প্রদর্শন করে:

 Objects
               Views:     142         ViewRootImpl:        1
         AppContexts:       3           Activities:        1
              Assets:      12        AssetManagers:        0
       Local Binders:      32        Proxy Binders:       45
       Parcel memory:      15         Parcel count:       30
    Death Recipients:       2             WebViews:        1

লক্ষ্যযুক্ত ব্যবহারকারী ইন্টারঅ্যাকশনটি (যেমন একটি ওয়েব স্ক্রিন খোলা এবং বন্ধ করা) বারবার সম্পাদন করুন এবং সংখ্যাগুলো তুলনা করুন:

  • ইনস্ট্যান্স লিক: যদি প্রতিটি নেভিগেশনের সময় WebViews বা Activities মেমরি বৃদ্ধি পায় এবং তা বেসলাইনে ফিরে না আসে, তাহলে আপনার অ্যাপে জাভা র‍্যাপার বা হোস্ট Activity মেমরি লিক হচ্ছে (উদাহরণস্বরূপ, ViewGroup.removeView() ফাংশনটি অনুপস্থিত থাকা বা লিসেনার রেফারেন্স ধরে রাখা)। যেহেতু একটি লিক হওয়া Activity তার সম্পূর্ণ ভিউ ট্রি এবং ডিকোড করা ইমেজ রিসোর্স মেমরিতে আটকে রাখে, তাই বারবার ব্যবহারের ফলে দ্রুত জাভা হিপ শেষ হয়ে যায় এবং OutOfMemoryError ক্র্যাশের কারণ হয়।

  • নেটিভ বা ডম লিক: যদি WebViews এবং Activities অপরিবর্তিত থাকে, কিন্তু মোট প্রসেস আরএসএস (RSS) এবং প্রাইভেট আদার (Private Other) ক্রমাগত বাড়তে থাকে, তাহলে এই লিকের উৎস হলো অপ্রকাশিত নেটিভ রিসোর্স, ডম এলিমেন্ট বা জাভাস্ক্রিপ্ট ইঞ্জিন বাইন্ডিং। যেহেতু এই অ্যালোকেশনগুলো নেটিভ মেমরিতে থাকে এবং এআরটি (ART) গার্বেজ কালেক্টরকে এড়িয়ে যায়, তাই এগুলো সাধারণ জাভা লিক ডিটেকশন টুলগুলোর কাছে অদৃশ্য থাকে এবং অপারেটিং সিস্টেম অ্যাপটি বন্ধ না করা পর্যন্ত জমা হতে থাকে।

CLI ব্যবহার করে বিচ্ছিন্ন রেন্ডারার প্রসেসের প্রোফাইল তৈরি করুন

আপনার অ্যাপের প্যাকেজ নাম দিয়ে dumpsys meminfo চালালে শুধুমাত্র প্রধান হোস্ট প্রসেসের মেমরি আউটপুট পাওয়া যায়। যে আইসোলেটেড রেন্ডারার প্রসেসে ওয়েব পেজ রেন্ডার করা হয়, সেটি পরীক্ষা করতে:

  1. আইসোলেটেড রেন্ডারার সার্ভিসের প্রসেস আইডি (PID) খুঁজুন:

    adb shell dumpsys activity processes <var>PACKAGE_NAME</var> | grep "Isolated.*SandboxedProcessService"

    আউটপুটে বিচ্ছিন্ন প্রসেস রেকর্ড এবং এর পিআইডি (উদাহরণস্বরূপ, 22155 ) প্রদর্শিত হয়:

    Isolated #5: ProcessRecord{... 22155:com.google.android.webview.debug:sandboxed_process0:...}
    
  2. এর PID ব্যবহার করে রেন্ডারার প্রসেসটির মেমরি বিভাজন পরীক্ষা করুন:

    adb shell dumpsys meminfo <var>RENDERER_PID</var>
  3. ব্রাউজার-সাইড ফুটপ্রিন্ট মূল্যায়ন করতে হোস্ট অ্যাপ প্রসেসটি পরিদর্শন করুন:

    adb shell dumpsys meminfo <var>PACKAGE_NAME</var>

মেমরি ম্যাপ এবং বরাদ্দ পরিদর্শন করুন

কোন নেটিভ সাবসিস্টেম বা অ্যালোকেটরগুলো অ্যানোনিমাস মেমরি দখল করে আছে তা দেখতে, প্রসেস মেমরি ম্যাপগুলো পরীক্ষা করুন:

adb shell "cat /proc/$(pidof <var>PACKAGE_NAME</var>)/maps" | grep "anon:"

নিম্নলিখিত সারণিতে সাধারণ বেনামী স্মৃতি ট্যাগ এবং স্মৃতি বিকাশে তাদের প্রাসঙ্গিকতা তালিকাভুক্ত করা হয়েছে:

মেমরি ট্যাগ সাবসিস্টেম অ্যাপ এবং ওয়েব কন্টেন্টের সাথে প্রাসঙ্গিকতা স্মৃতিশক্তি বৃদ্ধির সাধারণ কারণ কী?
[anon:partition_alloc] ক্রোমিয়াম পার্টিশনঅ্যালোক WebView তে DOM ট্রি, রেন্ডারিং বাফার, V8 জাভাস্ক্রিপ্ট হিপ এবং WebAssembly এক্সিকিউশনের জন্য মেমোরি বরাদ্দ। হ্যাঁ (উচ্চ): ভারী ওয়েব পেজ, মিডিয়া-সমৃদ্ধ DOM লোড করা, অথবা বাতিল করা WebView ইনস্ট্যান্সগুলিতে destroy() কল করতে ব্যর্থ হলে সরাসরি এই ট্যাগটি স্ফীত হয়।
[anon:scudo...] অথবা [anon:libc_malloc] অ্যান্ড্রয়েড নেটিভ হিপ অ্যালোকেটর ( স্কুডো / জেম্যালক) এনডিকে লাইব্রেরি, জেএনআই ব্রিজ এবং নেটিভ গ্রাফিক্স পাইপলাইন দ্বারা ব্যবহৃত সাধারণ সি/সি++ নেটিভ অ্যালোকেশন। হ্যাঁ (মাঝারি থেকে উচ্চ): যখন নেটিভ JNI র‍্যাপার বা তৃতীয় পক্ষের C++ ডিপেন্ডেন্সিগুলো নেভিগেশন জুড়ে অপ্রকাশিত অ্যালোকেশন ধরে রাখে, তখন এই বৃদ্ধি ঘটে।
[anon:...] (উদাহরণস্বরূপ, [anon:quickjs_heap...] ) কাস্টম স্ক্রিপ্টিং বা নেটিভ রানটাইম এমবেডেড জাভাস্ক্রিপ্ট ইঞ্জিন, কাস্টম ওয়েবঅ্যাসেম্বলি রানটাইম, অথবা কাস্টম নেটিভ বাফার পুল। হ্যাঁ (প্রসঙ্গ-নির্ভর): এটি হাইব্রিড অ্যাপের ক্ষেত্রে সাধারণ, যেগুলো নেটিভ ভিউয়ের পাশাপাশি স্ক্রিপ্টিং ইঞ্জিন চালায় এবং রানটাইম বাইন্ডিংগুলো পরিষ্কার করতে ব্যর্থ হয়।

ইন-অ্যাপ মেমরি এপিআই-এর সীমাবদ্ধতা

অ্যাপের ভেতরের মেমরি এপিআই (যেমন Debug.getMemoryInfo বা ActivityManager.getProcessMemoryInfo ) শুধুমাত্র কলিং প্রসেসের মেমরি পরিমাপ করে। মাল্টি-প্রসেস মোডে, এই এপিআইগুলো আলাদা রেন্ডারার প্রসেসের ব্যবহৃত মেমরি পরিমাপ করতে পারে না। মোট মেমরির সঠিক মূল্যায়নের জন্য dumpsys meminfo , Perfetto বা Android Studio Profiler-এর মতো সিস্টেম টুলগুলোর ওপর নির্ভর করুন।

হাইব্রিড অ্যাপে উচ্চ মেমরি বাছাই করা

বারবার ব্যবহৃত WebView ইন্টারঅ্যাকশনের (যেমন ওয়েব লিঙ্ক খোলা বা ওয়েব-চালিত ফিড নেভিগেট করা) সময় ব্যাখ্যাতীত মেমরি বৃদ্ধি নির্ণয় করার ক্ষেত্রে, মেমরি লিকটি জাভা লেয়ার থেকে নাকি নেটিভ ইঞ্জিন থেকে উদ্ভূত হচ্ছে তা আলাদা করতে নিম্নলিখিত ট্রায়েজ ওয়ার্কফ্লোটি ব্যবহার করুন:

  1. লিকের ধরন (জাভা বনাম নেটিভ) শনাক্ত করুন: ব্যবহারকারীর বারবার বিভিন্ন কাজে অংশগ্রহণের (যেমন ওয়েব আর্টিকেল খোলা ও বন্ধ করা বা ফিড সোয়াইপ করা) আগে ও পরে dumpsys meminfo -a <var>PACKAGE_NAME</var> | grep -A 10 "Objects" চালান।

    • পর্যবেক্ষণ: যদি Activities এবং WebViews সংখ্যা স্থির থাকে (উদাহরণস্বরূপ, ১-২টি সক্রিয় ইনস্ট্যান্স), তাহলে অ্যাপটি Activity কনটেক্সট বা জাভা WebView র‍্যাপার লিক করছে না।
  2. একাধিক ব্যবহারকারীর ইন্টারঅ্যাকশন জুড়ে মেমরি ডেল্টা পরিমাপ করুন (টাইম-সিরিজ ট্র্যাকিং): প্রতি ট্রানজিশনে অ্যালোকেশন রেট গণনা করতে একাধিক ব্যবহারকারীর ইন্টারঅ্যাকশন জুড়ে dumpsys meminfo স্ন্যাপশট ক্যাপচার করুন:

    • পর্যবেক্ষণ: জাভা হিপ সীমিত এবং সুস্থ থাকে (ব্যবহারের সময় বৃদ্ধি পায় এবং গার্বেজ কালেকশনের পরে কমে যায়), কিন্তু প্রাইভেট আদার এবং নেটিভ হিপ প্রতি ট্রানজিশনে কয়েক মেগাবাইট করে ক্রমাগত বাড়তে থাকে। এটি প্রমাণ করে যে মেমরি লিকটি সম্পূর্ণরূপে ART রানটাইমের বাইরের নেটিভ মেমরিতে হচ্ছে। স্ট্যান্ডার্ড জাভা হিপ ডাম্প ( .hprof ) ফাইলে কোনো সমস্যা দেখা যাবে না।
  3. অ্যানোনিমাস মেমরি ম্যাপ পরিদর্শন করুন: ADB ব্যবহার করে প্রসেস মেমরি ম্যাপ পরীক্ষা করুন ( মেমরি ম্যাপ এবং অ্যালোকেশন পরিদর্শন দেখুন):

    adb shell "cat /proc/$(pidof <var>PACKAGE_NAME</var>)/maps" | grep "anon:"
    • পর্যবেক্ষণ: মেমোরির বৃদ্ধি [anon:partition_alloc] অথবা এমবেডেড স্ক্রিপ্টিং ইঞ্জিন হিপ-এ কেন্দ্রীভূত, যার সাথে JNI গ্লোবাল রেফারেন্সের ধীর বৃদ্ধি পরিলক্ষিত হয়। এটি নির্দেশ করে যে, যদিও জাভা ভিউগুলো প্রতিস্থাপিত হয়েছিল, কিন্তু অন্তর্নিহিত নেটিভ পেজ অবজেক্ট বা জাভাস্ক্রিপ্ট বাইন্ডিংগুলো মুক্ত করা হয়নি।
  4. প্রতিকার:

    • নিশ্চিত করুন যে প্রতিটি রিসাইকেল করা বা বাতিল করা WebView সক্রিয় স্ক্রিপ্টগুলিকে স্পষ্টভাবে বন্ধ করে ( stopLoading() ), হিস্ট্রি মুছে ফেলে এবং destroy() কল করে।
    • বাতিল করা ভিউগুলির সাথে যুক্ত কাস্টম জাভাস্ক্রিপ্ট ব্রিজ কলব্যাক বা JNI গ্লোবাল রেফারেন্সগুলি নিষ্ক্রিয় করুন।
    • নেভিগেশন পরিবর্তনের পর Private Other এবং প্রসেস আরএসএস স্থিতিশীল হয় কিনা তা নিশ্চিত করুন।

অতিরিক্ত সম্পদ

মেমরি এবং WebView পারফরম্যান্স ডিবাগিং ও প্রোফাইলিং সম্পর্কে আরও জানতে, নিম্নলিখিত রিসোর্সগুলো দেখুন:

,

আপনার অ্যান্ড্রয়েড অ্যাপে ওয়েব কন্টেন্ট রেন্ডার করার জন্য WebView একাধিক প্রসেস জুড়ে নেটিভ কোড চালায়। WebView ইনস্ট্যান্সগুলোকে অব্যবস্থাপিত রাখলে মেমরি লিক, আউট-অফ-মেমরি (OOM) ক্র্যাশ এবং অ্যাপের পারফরম্যান্স হ্রাস পেতে পারে।

এই ডকুমেন্টটি WebView মাল্টি-প্রসেস মেমরি মডেল ব্যাখ্যা করে, মেমরি লিক প্রতিরোধ করার জন্য এর লাইফসাইকেল কীভাবে সঠিকভাবে পরিচালনা করতে হয় তা বর্ণনা করে এবং মেমরি সংক্রান্ত সমস্যা নির্ণয়ের জন্য ব্যবহারিক ওয়ার্কফ্লো প্রদান করে।

WebView মেমরি আর্কিটেকচার বুঝুন

WebView মেমরি কার্যকরভাবে পরিচালনা করতে, অ্যান্ড্রয়েড কীভাবে ওয়েব কন্টেন্টের জন্য রিসোর্স বরাদ্দ করে তা বুঝুন:

  • মাল্টি-প্রসেস এক্সিকিউশন: অ্যান্ড্রয়েড ৮.০ (এপিআই লেভেল ২৬) এবং এর পরবর্তী সংস্করণগুলোতে, WebView আপনার অ্যাপের মূল ফাংশনগুলো থেকে ওয়েব কন্টেন্টকে একাধিক প্রসেসে আলাদা করে রাখে (কম র‍্যামের ডিভাইসে এটি একটিমাত্র প্রসেসে ফিরে যেতে পারে):

    • হোস্ট (ব্রাউজার) প্রসেস: অ্যাপের প্রধান প্রসেস, যেখানে আপনার Activity এবং জাভা বা কোটলিন কোড চলে।
    • বিচ্ছিন্ন রেন্ডারার প্রসেস: একটি পৃথক স্যান্ডবক্সড প্রসেস ( SandboxedProcessService ) যা HTML ও CSS পার্স করে, জাভাস্ক্রিপ্ট এক্সিকিউট করে এবং ওয়েব পেজ রেন্ডার করে।
  • নেটিভ মেমরি ফুটপ্রিন্ট: WebView বেশিরভাগ মেমরি—রেন্ডার করা গ্রাফিক্স, DOM ট্রি এবং জাভাস্ক্রিপ্ট রানটাইম মেমরি সহ—জাভা হিপে নয়, বরং নেটিভ মেমরিতে বরাদ্দ করা হয়। একটি জাভা হিপ ডাম্প ( .hprof ) শুধুমাত্র একটি লাইটওয়েট জাভা র‍্যাপার অবজেক্ট দেখায় এবং ওয়েব কন্টেন্ট দ্বারা ব্যবহৃত প্রকৃত মেমরি ধারণ করে না।

  • নেটিভ মেমরির সিস্টেমগত ​​প্রভাব: জাভা হিপ অ্যালোকেশনের মতো নয়, যা অ্যাপের maxHeap লিমিট দ্বারা সীমাবদ্ধ থাকে এবং OutOfMemoryError দেখিয়ে দ্রুত ব্যর্থ হয়, নেটিভ মেমরি নীরবে গিগাবাইট পর্যন্ত বাড়তে পারে। যখন অব্যবহৃত নেটিভ মেমরি ফিজিক্যাল র‍্যাম এবং সোয়াপ স্পেস (zRAM) পূর্ণ করে ফেলে, তখন অ্যান্ড্রয়েডের লো মেমরি কিলার (LMK) মেমরি পুনরুদ্ধারের জন্য ব্যাকগ্রাউন্ড প্রসেসগুলো বন্ধ করতে শুরু করে। এটি ফোরগ্রাউন্ড অ্যাপটিকে পুরোপুরি বন্ধ করে দেওয়ার আগে ডিভাইসের সার্বিক মাল্টিটাস্কিংয়ের মান কমিয়ে দেয়।

WebView-এর জীবনচক্র পরিচালনা করুন

মেমরি লিক প্রতিরোধের জন্য সঠিক লাইফসাইকেল ম্যানেজমেন্ট অত্যন্ত গুরুত্বপূর্ণ। একটি সাধারণ ভুল ধারণা হলো যে, আপনার লেআউট থেকে একটি WebView সরিয়ে ফেললে বা একটি Activity শেষ হতে দিলে তার মেমরি স্বয়ংক্রিয়ভাবে মুক্ত হয়ে যায়।

WebView ইনস্ট্যান্সগুলি পরিষ্কার করুন

আপনার Activity বা Fragment ধ্বংস হয়ে গেলে একটি সুষ্ঠু শাটডাউন নিশ্চিত করতে এবং রিসোর্স মুক্ত করতে:

  1. WebView টিকে তার প্যারেন্ট কন্টেইনার ( ViewGroup ) থেকে সরিয়ে ফেলুন।
  2. সক্রিয় লোডিং বন্ধ করুন এবং নেভিগেশন ইতিহাস মুছে ফেলুন।
  3. destroy() কল করুন।
  4. null এর উল্লেখটি মুছে ফেলুন।

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি WebView সঠিকভাবে পরিষ্কার করতে হয়:

কোটলিন

override fun onDestroy() {
    myWebView?.let {
        // Remove the WebView from its parent ViewGroup.
        (it.parent as? ViewGroup)?.removeView(it)
        // Stop active loading and clear history.
        it.stopLoading()
        it.clearHistory()
        // Destroy the instance.
        it.destroy()
    }
    myWebView = null
    super.onDestroy()
}

জাভা

@Override
protected void onDestroy() {
    if (myWebView != null) {
        // Remove the WebView from its parent ViewGroup.
        if (myWebView.getParent() instanceof ViewGroup) {
            ((ViewGroup) myWebView.getParent()).removeView(myWebView);
        }
        // Stop active loading and clear history.
        myWebView.stopLoading();
        myWebView.clearHistory();
        // Destroy the instance.
        myWebView.destroy();
    }
    myWebView = null;
    super.onDestroy();
}

ধ্বংস-পরবর্তী স্মৃতি বুঝুন

যখন আপনি destroy() কল করেন, তখন সিস্টেম Activity কনটেক্সট মুক্ত করে, ভিউ হায়ারার্কিগুলো পরিষ্কার করে এবং ওয়েব ব্যাকগ্রাউন্ডের কাজ বন্ধ করে দেয়। তবে, আপনি লক্ষ্য করতে পারেন যে প্রসেসটির ফিজিক্যাল মেমরি (রেসিডেন্ট সেট সাইজ) সঙ্গে সঙ্গে তার WebView-পূর্ববর্তী বেসলাইনে নেমে আসে না।

এই আচরণটি স্বাভাবিক। নেটিভ রানটাইম ক্যাশ, শেয়ার্ড লাইব্রেরি এবং বরাদ্দকৃত মেমরি পেজগুলো প্রসেসের মধ্যেই থেকে যায়, যতক্ষণ না অপারেটিং সিস্টেম সেগুলোকে পুনরুদ্ধার করে অথবা প্রসেসটি বন্ধ হয়ে যায়। destroy() ফাংশনের প্রধান উদ্দেশ্য হলো, ব্যবহারকারীরা যখন ওয়েব-চালিত স্ক্রিনগুলোতে প্রবেশ করে ও বের হয়, তখন Activity ক্রমবর্ধমান মেমরি লিক প্রতিরোধ করা।

মূল ডিবাগিং মেট্রিক্স

WebView মেমরি ব্যবহার বিশ্লেষণ করার সময়, নিম্নলিখিত মেট্রিকগুলোর উপর মনোযোগ দিন:

  • রেসিডেন্ট সেট সাইজ (RSS): প্রসেসটিতে ম্যাপ করা মোট ফিজিক্যাল র‍্যাম, যার মধ্যে শেয়ার্ড কোড এবং লাইব্রেরি অন্তর্ভুক্ত থাকে (অ্যান্ড্রয়েড স্টুডিও প্রোফাইলার-এ এটিকে 'Total' হিসেবে চিহ্নিত করা হয়)।

  • অ্যানোনিমাস আরএসএস (RssAnon): প্রসেস দ্বারা সরাসরি বরাদ্দকৃত মেমরি, যা ডিস্কের কোনো ফাইল দ্বারা সমর্থিত নয় (যেমন নেটিভ হিপ এবং জাভাস্ক্রিপ্ট রানটাইম অ্যালোকেশন)। এটি আপনার ওয়েব কন্টেন্টের প্রধান মেমরি খরচকে নির্দেশ করে (অ্যান্ড্রয়েড স্টুডিও প্রোফাইলার-এ এটিকে 'Allocated' হিসেবে চিহ্নিত করা হয়)।

  • প্রাইভেট মেমোরি ফুটপ্রিন্ট (PMF): অ্যানোনিমাস RSS এবং সোয়াপ (zRAM)-এর সমষ্টি। PMF আপনার অ্যাপ দ্বারা সিস্টেমের উপর আরোপিত প্রকৃত ও অপসারণ-অযোগ্য মেমোরির বোঝা প্রতিফলিত করে।

  • ব্রাউজার পিএমএফ বনাম রেন্ডারার পিএমএফ: আপনার অ্যাপের প্রধান প্রসেস দ্বারা ব্যবহৃত মেমরি বনাম বিচ্ছিন্ন রেন্ডারার প্রসেস দ্বারা ব্যবহৃত মেমরি। ভারী ওয়েব কন্টেন্টের কারণে প্রধানত রেন্ডারার প্রসেসেই মেমরি ব্যবহারের আকস্মিক বৃদ্ধি ঘটে।

  • লাইভ অবজেক্ট কাউন্ট ( WebViews , Activities , Views ): মেমরিতে থাকা সক্রিয় UI, কনটেক্সট এবং WebView ইনস্ট্যান্সের সংখ্যা। এগুলি ট্র্যাক করার মাধ্যমে শনাক্ত করা যায় যে, মেমরির এই বৃদ্ধি রিটেইনড জাভা রেফারেন্সের কারণে হচ্ছে, নাকি শুধুমাত্র নেটিভ অ্যালোকেশনের কারণে।

  • প্রাইভেট আদার এবং নেটিভ হিপ: dumpsys meminfo তে, নেটিভ C/C++ অ্যালোকেশন এবং কাস্টম মেমরি ম্যাপিং (যেমন Chromium PartitionAlloc বা এমবেডেড জাভাস্ক্রিপ্ট রানটাইম হিপ) Java Heap-এর পরিবর্তে Native Heap এবং Private Other-এর অধীনে প্রদর্শিত হয়।

প্রসেস মেমরি কাউন্টার এবং তাদের শ্রেণীবিভাগ সম্পর্কে আরও তথ্যের জন্য, প্রসেস মেমরি শব্দকোষ দেখুন।

ব্যবহারিক রোগনির্ণয় কর্মপ্রবাহ

যেহেতু WebView একাধিক প্রসেস জুড়ে কাজ করে এবং নিজস্ব মেমরি বরাদ্দ করে, তাই এর ফুটপ্রিন্ট পরীক্ষা করার জন্য নিম্নলিখিত টুল এবং কৌশলগুলো ব্যবহার করুন:

প্রোফাইলিং এবং ডায়াগনস্টিক সরঞ্জাম

মেমরি অ্যালোকেশন পরিদর্শন করতে এবং মেমরি লিক নির্ণয় করতে নিম্নলিখিত টুলগুলি ব্যবহার করুন:

  • অ্যান্ড্রয়েড স্টুডিও মেমরি প্রোফাইলার: নেটিভ অ্যালোকেশনগুলো দেখতে, সময়ের সাথে সাথে মেমরির বিভিন্ন ক্যাটাগরি ট্র্যাক করতে এবং স্ক্রিন পরিবর্তনের সময় Activity মেমরি লিক শনাক্ত করতে মেমরি প্রোফাইলার ব্যবহার করুন।

  • পারফেট্টো দিয়ে মেমরি ট্র্যাকিং: সামগ্রিক মেমরি বৃদ্ধি পর্যবেক্ষণ করতে পারফেট্টো ব্যবহার করে সিস্টেম-স্তরের মেমরি কাউন্টার (যেমন RSS এবং Anonymous RSS) রেকর্ড করুন। মনে রাখবেন যে WebView নেটিভ ইঞ্জিন অ্যালোকেশন পারফেট্টোর হিপ প্রোফাইলিং টুলে কলস্ট্যাক তৈরি করে না। ওয়েব কন্টেন্টের ভেতরের জাভাস্ক্রিপ্ট হিপ স্ন্যাপশট এবং DOM অ্যালোকেশন পরীক্ষা করতে Chrome DevTools ব্যবহার করুন।

লাইভ অবজেক্ট সংখ্যা পরিদর্শন করুন

মেমোরি বৃদ্ধি অবশিষ্ট জাভা র‍্যাপার বা নেটিভ অ্যালোকেশনের কারণে হচ্ছে কিনা তা নির্ধারণ করতে, dumpsys meminfo এর Objects অংশটি পরীক্ষা করুন:

adb shell dumpsys meminfo -a <var>PACKAGE_NAME</var> | grep -A 10 "Objects"

আউটপুটটি লাইভ অবজেক্ট সংখ্যা প্রদর্শন করে:

 Objects
               Views:     142         ViewRootImpl:        1
         AppContexts:       3           Activities:        1
              Assets:      12        AssetManagers:        0
       Local Binders:      32        Proxy Binders:       45
       Parcel memory:      15         Parcel count:       30
    Death Recipients:       2             WebViews:        1

লক্ষ্যযুক্ত ব্যবহারকারী ইন্টারঅ্যাকশনটি (যেমন একটি ওয়েব স্ক্রিন খোলা এবং বন্ধ করা) বারবার সম্পাদন করুন এবং সংখ্যাগুলো তুলনা করুন:

  • ইনস্ট্যান্স লিক: যদি প্রতিটি নেভিগেশনের সময় WebViews বা Activities মেমরি বৃদ্ধি পায় এবং তা বেসলাইনে ফিরে না আসে, তাহলে আপনার অ্যাপে জাভা র‍্যাপার বা হোস্ট Activity মেমরি লিক হচ্ছে (উদাহরণস্বরূপ, ViewGroup.removeView() ফাংশনটি অনুপস্থিত থাকা বা লিসেনার রেফারেন্স ধরে রাখা)। যেহেতু একটি লিক হওয়া Activity তার সম্পূর্ণ ভিউ ট্রি এবং ডিকোড করা ইমেজ রিসোর্স মেমরিতে আটকে রাখে, তাই বারবার ব্যবহারের ফলে দ্রুত জাভা হিপ শেষ হয়ে যায় এবং OutOfMemoryError ক্র্যাশের কারণ হয়।

  • নেটিভ বা ডম লিক: যদি WebViews এবং Activities অপরিবর্তিত থাকে, কিন্তু মোট প্রসেস আরএসএস (RSS) এবং প্রাইভেট আদার (Private Other) ক্রমাগত বাড়তে থাকে, তাহলে এই লিকের উৎস হলো অপ্রকাশিত নেটিভ রিসোর্স, ডম এলিমেন্ট বা জাভাস্ক্রিপ্ট ইঞ্জিন বাইন্ডিং। যেহেতু এই অ্যালোকেশনগুলো নেটিভ মেমরিতে থাকে এবং এআরটি (ART) গার্বেজ কালেক্টরকে এড়িয়ে যায়, তাই এগুলো সাধারণ জাভা লিক ডিটেকশন টুলগুলোর কাছে অদৃশ্য থাকে এবং অপারেটিং সিস্টেম অ্যাপটি বন্ধ না করা পর্যন্ত জমা হতে থাকে।

CLI ব্যবহার করে বিচ্ছিন্ন রেন্ডারার প্রসেসের প্রোফাইল তৈরি করুন

আপনার অ্যাপের প্যাকেজ নাম দিয়ে dumpsys meminfo চালালে শুধুমাত্র প্রধান হোস্ট প্রসেসের মেমরি আউটপুট পাওয়া যায়। যে আইসোলেটেড রেন্ডারার প্রসেসে ওয়েব পেজ রেন্ডার করা হয়, সেটি পরীক্ষা করতে:

  1. আইসোলেটেড রেন্ডারার সার্ভিসের প্রসেস আইডি (PID) খুঁজুন:

    adb shell dumpsys activity processes <var>PACKAGE_NAME</var> | grep "Isolated.*SandboxedProcessService"

    আউটপুটে বিচ্ছিন্ন প্রসেস রেকর্ড এবং এর পিআইডি (উদাহরণস্বরূপ, 22155 ) প্রদর্শিত হয়:

    Isolated #5: ProcessRecord{... 22155:com.google.android.webview.debug:sandboxed_process0:...}
    
  2. এর PID ব্যবহার করে রেন্ডারার প্রসেসটির মেমরি বিভাজন পরীক্ষা করুন:

    adb shell dumpsys meminfo <var>RENDERER_PID</var>
  3. ব্রাউজার-সাইড ফুটপ্রিন্ট মূল্যায়ন করতে হোস্ট অ্যাপ প্রসেসটি পরিদর্শন করুন:

    adb shell dumpsys meminfo <var>PACKAGE_NAME</var>

মেমরি ম্যাপ এবং বরাদ্দ পরিদর্শন করুন

কোন নেটিভ সাবসিস্টেম বা অ্যালোকেটরগুলো অ্যানোনিমাস মেমরি দখল করে আছে তা দেখতে, প্রসেস মেমরি ম্যাপগুলো পরীক্ষা করুন:

adb shell "cat /proc/$(pidof <var>PACKAGE_NAME</var>)/maps" | grep "anon:"

নিম্নলিখিত সারণিতে সাধারণ বেনামী স্মৃতি ট্যাগ এবং স্মৃতি বিকাশে তাদের প্রাসঙ্গিকতা তালিকাভুক্ত করা হয়েছে:

মেমরি ট্যাগ সাবসিস্টেম অ্যাপ এবং ওয়েব কন্টেন্টের সাথে প্রাসঙ্গিকতা স্মৃতিশক্তি বৃদ্ধির সাধারণ কারণ কী?
[anon:partition_alloc] ক্রোমিয়াম পার্টিশনঅ্যালোক WebView তে DOM ট্রি, রেন্ডারিং বাফার, V8 জাভাস্ক্রিপ্ট হিপ এবং WebAssembly এক্সিকিউশনের জন্য মেমোরি বরাদ্দ। হ্যাঁ (উচ্চ): ভারী ওয়েব পেজ, মিডিয়া-সমৃদ্ধ DOM লোড করা, অথবা বাতিল করা WebView ইনস্ট্যান্সগুলিতে destroy() কল করতে ব্যর্থ হলে সরাসরি এই ট্যাগটি স্ফীত হয়।
[anon:scudo...] অথবা [anon:libc_malloc] অ্যান্ড্রয়েড নেটিভ হিপ অ্যালোকেটর ( স্কুডো / জেম্যালক) এনডিকে লাইব্রেরি, জেএনআই ব্রিজ এবং নেটিভ গ্রাফিক্স পাইপলাইন দ্বারা ব্যবহৃত সাধারণ সি/সি++ নেটিভ অ্যালোকেশন। হ্যাঁ (মাঝারি থেকে উচ্চ): যখন নেটিভ JNI র‍্যাপার বা তৃতীয় পক্ষের C++ ডিপেন্ডেন্সিগুলো নেভিগেশন জুড়ে অপ্রকাশিত অ্যালোকেশন ধরে রাখে, তখন এই বৃদ্ধি ঘটে।
[anon:...] (উদাহরণস্বরূপ, [anon:quickjs_heap...] ) কাস্টম স্ক্রিপ্টিং বা নেটিভ রানটাইম এমবেডেড জাভাস্ক্রিপ্ট ইঞ্জিন, কাস্টম ওয়েবঅ্যাসেম্বলি রানটাইম, অথবা কাস্টম নেটিভ বাফার পুল। হ্যাঁ (প্রসঙ্গ-নির্ভর): এটি হাইব্রিড অ্যাপের ক্ষেত্রে সাধারণ, যেগুলো নেটিভ ভিউয়ের পাশাপাশি স্ক্রিপ্টিং ইঞ্জিন চালায় এবং রানটাইম বাইন্ডিংগুলো পরিষ্কার করতে ব্যর্থ হয়।

ইন-অ্যাপ মেমরি এপিআই-এর সীমাবদ্ধতা

অ্যাপের ভেতরের মেমরি এপিআই (যেমন Debug.getMemoryInfo বা ActivityManager.getProcessMemoryInfo ) শুধুমাত্র কলিং প্রসেসের মেমরি পরিমাপ করে। মাল্টি-প্রসেস মোডে, এই এপিআইগুলো আলাদা রেন্ডারার প্রসেসের ব্যবহৃত মেমরি পরিমাপ করতে পারে না। মোট মেমরির সঠিক মূল্যায়নের জন্য dumpsys meminfo , Perfetto বা Android Studio Profiler-এর মতো সিস্টেম টুলগুলোর ওপর নির্ভর করুন।

হাইব্রিড অ্যাপে উচ্চ মেমরি বাছাই করা

বারবার ব্যবহৃত WebView ইন্টারঅ্যাকশনের (যেমন ওয়েব লিঙ্ক খোলা বা ওয়েব-চালিত ফিড নেভিগেট করা) সময় ব্যাখ্যাতীত মেমরি বৃদ্ধি নির্ণয় করার ক্ষেত্রে, মেমরি লিকটি জাভা লেয়ার থেকে নাকি নেটিভ ইঞ্জিন থেকে উদ্ভূত হচ্ছে তা আলাদা করতে নিম্নলিখিত ট্রায়েজ ওয়ার্কফ্লোটি ব্যবহার করুন:

  1. লিকের ধরন (জাভা বনাম নেটিভ) শনাক্ত করুন: ব্যবহারকারীর বারবার বিভিন্ন কাজে অংশগ্রহণের (যেমন ওয়েব আর্টিকেল খোলা ও বন্ধ করা বা ফিড সোয়াইপ করা) আগে ও পরে dumpsys meminfo -a <var>PACKAGE_NAME</var> | grep -A 10 "Objects" চালান।

    • পর্যবেক্ষণ: যদি Activities এবং WebViews সংখ্যা স্থির থাকে (উদাহরণস্বরূপ, ১-২টি সক্রিয় ইনস্ট্যান্স), তাহলে অ্যাপটি Activity কনটেক্সট বা জাভা WebView র‍্যাপার লিক করছে না।
  2. একাধিক ব্যবহারকারীর ইন্টারঅ্যাকশন জুড়ে মেমরি ডেল্টা পরিমাপ করুন (টাইম-সিরিজ ট্র্যাকিং): প্রতি ট্রানজিশনে অ্যালোকেশন রেট গণনা করতে একাধিক ব্যবহারকারীর ইন্টারঅ্যাকশন জুড়ে dumpsys meminfo স্ন্যাপশট ক্যাপচার করুন:

    • পর্যবেক্ষণ: জাভা হিপ সীমিত এবং সুস্থ থাকে (ব্যবহারের সময় বৃদ্ধি পায় এবং গার্বেজ কালেকশনের পরে কমে যায়), কিন্তু প্রাইভেট আদার এবং নেটিভ হিপ প্রতি ট্রানজিশনে কয়েক মেগাবাইট করে ক্রমাগত বাড়তে থাকে। এটি প্রমাণ করে যে মেমরি লিকটি সম্পূর্ণরূপে ART রানটাইমের বাইরের নেটিভ মেমরিতে হচ্ছে। স্ট্যান্ডার্ড জাভা হিপ ডাম্প ( .hprof ) ফাইলে কোনো সমস্যা দেখা যাবে না।
  3. অ্যানোনিমাস মেমরি ম্যাপ পরিদর্শন করুন: ADB ব্যবহার করে প্রসেস মেমরি ম্যাপ পরীক্ষা করুন ( মেমরি ম্যাপ এবং অ্যালোকেশন পরিদর্শন দেখুন):

    adb shell "cat /proc/$(pidof <var>PACKAGE_NAME</var>)/maps" | grep "anon:"
    • পর্যবেক্ষণ: মেমোরির বৃদ্ধি [anon:partition_alloc] অথবা এমবেডেড স্ক্রিপ্টিং ইঞ্জিন হিপ-এ কেন্দ্রীভূত, যার সাথে JNI গ্লোবাল রেফারেন্সের ধীর বৃদ্ধি পরিলক্ষিত হয়। এটি নির্দেশ করে যে, যদিও জাভা ভিউগুলো প্রতিস্থাপিত হয়েছিল, কিন্তু অন্তর্নিহিত নেটিভ পেজ অবজেক্ট বা জাভাস্ক্রিপ্ট বাইন্ডিংগুলো মুক্ত করা হয়নি।
  4. প্রতিকার:

    • নিশ্চিত করুন যে প্রতিটি রিসাইকেল করা বা বাতিল করা WebView সক্রিয় স্ক্রিপ্টগুলিকে স্পষ্টভাবে বন্ধ করে ( stopLoading() ), হিস্ট্রি মুছে ফেলে এবং destroy() কল করে।
    • বাতিল করা ভিউগুলির সাথে যুক্ত কাস্টম জাভাস্ক্রিপ্ট ব্রিজ কলব্যাক বা JNI গ্লোবাল রেফারেন্সগুলি নিষ্ক্রিয় করুন।
    • নেভিগেশন পরিবর্তনের পর Private Other এবং প্রসেস আরএসএস স্থিতিশীল হয় কিনা তা নিশ্চিত করুন।

অতিরিক্ত সম্পদ

মেমরি এবং WebView পারফরম্যান্স ডিবাগিং ও প্রোফাইলিং সম্পর্কে আরও জানতে, নিম্নলিখিত রিসোর্সগুলো দেখুন: