WebView একটি শক্তিশালী কম্পোনেন্ট যা আপনাকে আপনার অ্যান্ড্রয়েড অ্যাপ্লিকেশনের মধ্যে ওয়েব কন্টেন্ট প্রদর্শন করতে দেয়। তবে, যেহেতু এটি মূলত একটি পূর্ণাঙ্গ ব্রাউজার ইঞ্জিন (ক্রোমিয়াম), তাই এটি অনেক বেশি মেমরি ব্যবহার করে এবং এর একটি জটিল মাল্টি-প্রসেস আর্কিটেকচার রয়েছে।
প্রযুক্তিগত পটভূমি: মাল্টি-প্রসেস আর্কিটেকচার
আধুনিক অ্যান্ড্রয়েড-চালিত ডিভাইসগুলিতে, নিরাপত্তা ও স্থিতিশীলতা উন্নত করার জন্য ওয়েবভিউ একটি মাল্টি-প্রসেস মডেল ব্যবহার করে। যখন আপনার অ্যাপ একটি ওয়েবভিউ ব্যবহার করে, তখন মেমরি বিভিন্ন প্রসেসের মধ্যে ভাগ হয়ে যায়:
- ব্রাউজার প্রসেস (অ্যাপ প্রসেস) : এটি আপনার অ্যাপ্লিকেশনের প্রধান প্রসেস। এতে জাভা
WebViewঅবজেক্ট এবং ক্রোমিয়াম ইঞ্জিনের "ব্রাউজার" অংশটি থাকে। এই প্রসেসটি UI, নেটওয়ার্ক রিকোয়েস্ট এবং GPU রেন্ডারিং পরিচালনা করে (যা সরাসরি অ্যান্ড্রয়েড HWUI রেন্ডারিং পাইপলাইনের সাথে সমন্বিত)। ক্রোমের মতো নয়, WebView-এর কোনো আলাদা GPU প্রসেস নেই। - রেন্ডারার প্রসেস : এই প্রসেসটি এইচটিএমএল (HTML) পার্সিং, জাভাস্ক্রিপ্ট (JavaScript) এক্সিকিউশন এবং লেআউটের জন্য দায়ী। নিরাপত্তার কারণে এটিকে সিস্টেমের বাকি অংশ থেকে আলাদা রাখা হয়। বর্তমানে, অ্যাপগুলো সমস্ত ওয়েবভিউ (WebViews)-এর জন্য একটিমাত্র রেন্ডারার প্রসেস ব্যবহার করে (কিছু বিরল বিশেষ ক্ষেত্র ছাড়া), যা ক্রোমের থেকে ভিন্ন, কারণ ক্রোম প্রায়শই বিভিন্ন সাইটের জন্য আলাদা রেন্ডারার প্রসেস ব্যবহার করে।

স্মৃতির জন্য এটি কেন গুরুত্বপূর্ণ
যখন আপনি dumpsys meminfo <your_package> ব্যবহার করেন, তখন আপনি কেবল ব্রাউজার প্রসেস (আপনার অ্যাপ প্রসেস) দ্বারা ব্যবহৃত মেমরি দেখতে পান। রেন্ডারার প্রসেস দ্বারা ব্যবহৃত মেমরি আলাদাভাবে হিসাব করা হয়।
ব্রাউজার প্রসেসের ভিতরে, WebView-এর মেমরি নিম্নরূপে বণ্টিত হয়:
- জাভা হিপ : এতে
WebViewজাভা র্যাপার এবং সম্পর্কিত অবজেক্টগুলো থাকে। - নেটিভ হিপ : এতে ক্রোমিয়াম ব্রাউজার ইঞ্জিনের অভ্যন্তরীণ ডেটা স্ট্রাকচার, ক্যাশ এবং স্টেট থাকে। উল্লেখ্য যে, PartitionAlloc ব্যবহারের কারণে, কিছু WebView নেটিভ অ্যালোকেশন
dumpsys meminfoতে "নেটিভ হিপ"-এর অধীনে গণনা নাও হতে পারে এবং এর পরিবর্তে "অন্যান্য" বা "অজানা"-এর অধীনে প্রদর্শিত হতে পারে। - শেয়ার্ড মেমরি : গ্রাফিক্যাল বাফার এবং অন্যান্য ডেটা শেয়ার করার জন্য ব্যবহৃত হয়।
dumpsys meminfoদ্বারা এটি স্পষ্টভাবে শ্রেণীবদ্ধ নাও হতে পারে।
সমস্যা সমাধানের সরঞ্জাম
ক্রোম ডেভটুলস
WebView-এর ভেতরের মেমরি (রেন্ডারার প্রসেস) বিশ্লেষণ করার জন্য সবচেয়ে শক্তিশালী টুল হলো Chrome DevTools।
আপনার অ্যাপে WebView ডিবাগিং সক্ষম করুন:
// NOTE: In production, this should be gated behind a developer setting // or only enabled for debuggable builds to prevent reverse engineering. WebView.setWebContentsDebuggingEnabled(true);আপনার ডিভাইসটি ইউএসবি-র মাধ্যমে সংযুক্ত করুন।
আপনার হোস্ট মেশিনে Chrome খুলুন এবং
chrome://inspect/#devices-এ যান।আপনার অ্যাপটি খুঁজুন এবং 'ইনসপেক্ট'-এ ক্লিক করুন।
DevTools উইন্ডোতে, জাভাস্ক্রিপ্ট হিপের স্ন্যাপশট নিতে বা অ্যালোকেশন টাইমলাইন রেকর্ড করতে Memory ট্যাবে যান।
ডাম্পসিস মেমইনফো
মেমোরির বিস্তারিত বিবরণ দেখতে adb shell dumpsys meminfo --all <package> ব্যবহার করুন। আউটপুটে WebView ক্যাটাগরি এবং অবজেক্টের সংখ্যাগুলো দেখুন।
রেন্ডারারের প্রোফাইলিং
যেহেতু রেন্ডারার একটি আলাদা প্রসেসে চলে, তাই শুধু আপনার অ্যাপ প্রোফাইলিং করে আপনি এর নেটিভ হিপ প্রোফাইল করতে পারবেন না। আপনাকে অবশ্যই নির্দিষ্টভাবে রেন্ডারার প্রসেসটির পিআইডি (PID) শনাক্ত করতে হবে।
একাধিক ওয়েবভিউ সক্রিয় থাকলে সঠিক রেন্ডারার পিআইডি শনাক্ত করতে:
dumpsys activityব্যবহার করুন :adb shell dumpsys activity processes <your_package_name>mConnectionsসেকশনটি খুঁজুন। সেখানে আপনি একটিConnectionRecordদেখতে পাবেন, যা আপনার অ্যাপকে একটিSandboxedProcessServiceএর সাথে যুক্ত করে। সেই প্রসেসটির PID-ই হলো আপনার রেন্ডারার। উদাহরণ:mConnections: - ConnectionRecord{... com.android.memorylab/org.chromium.content.app.SandboxedProcessService0:0 ...}প্রসেসের নাম যাচাই করুন : রেন্ডারার প্রসেসগুলোর নাম সাধারণত
com.google.android.webview:sandboxed_processXবা এই ধরনের হয়ে থাকে। যদি কেবল একটি অ্যাপ WebView ব্যবহার করে, তবে সম্ভবত একটিই প্রসেস থাকবে।
একবার PID পেয়ে গেলে, আপনি heapprofd ব্যবহার করে সেটির প্রোফাইল তৈরি করতে পারবেন।
ওয়েবভিউ মেমরির জন্য সর্বোত্তম অনুশীলন
সুস্পষ্ট ধ্বংস
কোনো একটি ইনস্ট্যান্সের কাজ শেষ হয়ে গেলে, অ্যাপগুলোকে WebView.destroy() কল করে তা জানাতে হয়।
যদিও WebView নিশ্চিত করার চেষ্টা করে যে ইনস্ট্যান্সগুলো স্বয়ংক্রিয়ভাবে গার্বেজ কালেকশনের মাধ্যমে তাদের সমস্ত রিসোর্স মুক্ত করে দেবে, তবুও শতভাগ ক্ষেত্রে এর নিশ্চয়তা দেওয়া কঠিন। এমনকি যখন স্বয়ংক্রিয় গার্বেজ কালেকশন কাজ করে, তখনও এতে উল্লেখযোগ্য বিলম্ব হতে পারে, যার ফলে অ্যাপটি প্রত্যাশার চেয়ে অনেক বেশি সময় ধরে রিসোর্স ধরে রাখে।
যদি কোনো অ্যাপ সঠিক সময়ে WebView.destroy() কল করে (যেমন, Activity.onDestroy() ফাংশনে), তাহলে WebView অবজেক্টটির রেফারেন্স ধরে রাখলে উল্লেখযোগ্য কোনো নেটিভ রিসোর্স লিক হবে না। Activity অবজেক্টটি ডেস্ট্রয় করার পর এর ফিল্ডগুলোতে থাকা WebView অবজেক্টের রেফারেন্সগুলো null করে দেওয়ার কোনো কঠোর প্রয়োজন নেই, কারণ Activity-টি যখন গার্বেজ কালেক্টেড হয়, তখন এই রেফারেন্সগুলোও পরিষ্কার হয়ে যায়।
অনুশীলন: ওয়েবভিউ মেমরি নিয়ে হাতে-কলমে কাজ
অনুশীলন ১: একাধিক প্রক্রিয়ার পদচিহ্ন পর্যবেক্ষণ
MemoryLab চালু করুন এবং আপনার অ্যাপের মেমরির একটি বেসলাইন পরিমাপ নিন:
adb shell dumpsys meminfo com.android.memorylabনমুনা বেসলাইন (র্যাঙ্গো):
TOTAL PSS: 18915 KBলঞ্চ ওয়েবভিউ (নরমাল)-এ ট্যাপ করুন।
WebView-তে, Allocate JS Memory (1000 DIVs) অপশনটিতে কয়েকবার ট্যাপ করুন।
অ্যাপটির মেমরি আবার পরীক্ষা করুন:
adb shell dumpsys meminfo com.android.memorylabলক্ষ্য করুন যে আপনার অ্যাপ প্রসেসের মেমরি বেসলাইনের তুলনায় উল্লেখযোগ্যভাবে বৃদ্ধি পায় না! এর কারণ হলো DOM এলিমেন্টগুলো রেন্ডারার প্রসেসে থাকে।
রেন্ডারার প্রক্রিয়াটি খুঁজুন:
adb shell ps -A | grep webview | grep sandboxedউদাহরণ আউটপুট:
u0_i9002 14227 1087 1632732 135880 do_epoll_wait 0 S com.google.android.webview:sandboxed_process0রেন্ডারার প্রসেসটির মেমরি পরীক্ষা করুন (এর PID ব্যবহার করে):
adb shell dumpsys meminfo 14227রেন্ডারার প্রসেসের উচ্চ TOTAL PSS লক্ষ্য করুন। আমাদের নমুনা রানে, কয়েকটি অ্যালোকেশনের পর এটি প্রায় ৫৫ মেগাবাইটে পৌঁছে যায়। উল্লেখ্য যে, জাভাস্ক্রিপ্ট অ্যালোকেশন (যা V8 ইঞ্জিন দ্বারা পরিচালিত হয়) সাধারণত ডালভিক হিপে না গিয়ে,
dumpsys meminfoএর Private Other বা Unknown (mmap) সেকশনে যুক্ত হয়।
অনুশীলন ২: জাভা-সাইডের ওয়েবভিউ লিক
একটি সাধারণ ভুল হলো একটি WebView ইনস্ট্যান্সকে স্ট্যাটিক ফিল্ডে বা এমন কোনো দীর্ঘস্থায়ী অবজেক্টে ধরে রাখা যা মেমরি লিক করে। যেহেতু WebView অবজেক্টটি একটি ভারী 'অ্যাঙ্কর' যা নেটিভ রিসোর্স এবং সম্ভাব্য সম্পূর্ণ রেন্ডারার প্রসেসকে ধরে রাখে, তাই এটি লিক হওয়া অত্যন্ত ব্যয়বহুল।

- মেমোরিল্যাব- এ, লঞ্চ ওয়েবভিউ (জাভা লিক)-এ ট্যাপ করুন।
- পৃষ্ঠাটি লোড হওয়ার পরে কার্যকলাপটি স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যাবে (যা বারবার নেভিগেশন এবং লিকেজ জমা হওয়াকে অনুকরণ করে)।
- বাটনটিতে ৪ বার ট্যাপ করুন।
আপনার অ্যাপে
WebViewইনস্ট্যান্সের সংখ্যা পরীক্ষা করুন:adb shell dumpsys meminfo com.android.memorylabএকদম নিচে থাকা অবজেক্টস সেকশনটি দেখুন। আপনি দেখতে পাবেন যে
WebViewsএর সংখ্যা বেড়ে ৪ হয়েছে।rango-তে নমুনা আউটপুট (৪টি লিক হওয়া ইনস্ট্যান্স):
Objects Views: 51 ViewRootImpl: 5 AppContexts: 14 Activities: 5 Assets: 38 AssetManagers: 0 Local Binders: 55 Proxy Binders: 77 Parcel memory: 41 Parcel count: 68 Death Recipients: 3 WebViews: 4একটি হিপ ডাম্প ক্যাপচার করুন এবং লিকটি খুঁজে বের করতে AHAT ব্যবহার করুন। যদি আপনার পাথে
ahatনা থাকে, তবে আপনি অ্যান্ড্রয়েড ট্রি থেকে এটি বিল্ড করতে পারেন:# Dump heap from device adb shell am dumpheap com.android.memorylab /data/local/tmp/heap.hprof adb pull /data/local/tmp/heap.hprof # Run ahat using the built JAR (found in out/host/linux-x86/framework/) java -jar out/host/linux-x86/framework/ahat.jar -p 8888 heap.hprofAHAT ওয়েব ইন্টারফেসে (
localhost:8888), সামগ্রিক মেমরি ব্যবহার দেখতে উপরের মেনুতে থাকা অ্যালোকেশনস লিঙ্কে (বা সাইটস ) ক্লিক করুন।
android.webkit.WebViewক্লাসটি খুঁজুন। এর সমস্ত সক্রিয় ইনস্ট্যান্স দেখতে এর ইনস্ট্যান্স সংখ্যার উপর ক্লিক করুন। আপনি তালিকায় একাধিক ইনস্ট্যান্স দেখতে পাবেন।
লিক হওয়া
WebViewইনস্ট্যান্সগুলোর মধ্যে একটিতে ক্লিক করুন। নিচে স্ক্রল করে 'Sample Path from GC Root' সেকশন পর্যন্ত যান। আপনি দেখতে পাবেন যে এটিcom.android.memorylab.WebViewActivityএরsLeakedWebViewsলিস্ট দ্বারা ধারণ করা আছে।
← নেটিভ | ↑ উপরে | অ্যাপ কোড →