থ্রেড এবং মেমরি

প্রতিবার যখন আপনার অ্যাপ্লিকেশন একটি নতুন থ্রেড তৈরি করে, তখন সেটিকে সমর্থন করার জন্য অপারেটিং সিস্টেমকে মেমরি বরাদ্দ করতে হয়। যদিও পূর্ণাঙ্গ প্রসেসের তুলনায় থ্রেডগুলোকে সাধারণত "লাইটওয়েট" বা হালকা বলে মনে করা হয়, তবে এগুলোর মেমরি খরচ শূন্য নয়। অ্যান্ড্রয়েডে মেমরি লিক হওয়ার একটি খুব সাধারণ উপায় হলো থ্রেড লিক করা।

একটি সুতার দাম

অ্যান্ড্রয়েডে যখন একটি থ্রেড তৈরি করা হয়, তখন দুটি প্রধান উপাদান মেমরি ব্যবহার করে:

  1. নেটিভ স্ট্যাক : pthread লাইব্রেরি থ্রেডের জন্য লোকাল ভেরিয়েবল সংরক্ষণ এবং ফ্রেম কল করার জন্য একটি স্ট্যাক বরাদ্দ করে। অ্যান্ড্রয়েডে, এটি সাধারণত ডিফল্টরূপে ১ মেগাবাইট হয়ে থাকে।
  2. অভ্যন্তরীণ JVM/কার্নেল কাঠামো : থ্রেডকে ট্র্যাক ও পরিচালনা করার জন্য ART এবং লিনাক্স কার্নেলকে অবশ্যই ডেটা স্ট্রাকচার (যেমন pthread_internal_t ​​এবং java.lang.Thread অবজেক্ট) বরাদ্দ করতে হয়।

স্ট্যাক মেমরি এবং mmap

এটা বোঝা গুরুত্বপূর্ণ যে অ্যান্ড্রয়েড mmap ব্যবহার করে MAP_ANONYMOUS | MAP_NORESERVE ফ্ল্যাগগুলোর সাহায্যে ১ মেগাবাইট নেটিভ স্ট্যাক বরাদ্দ করে।

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

হাতে-কলমে অনুশীলন: লিক হওয়া সুতা

কোনো অ্যাপ্লিকেশন শত শত নিষ্ক্রিয় থ্রেড তৈরি করলে কী ঘটে, তা পর্যবেক্ষণ করতে আমরা মেমোরিল্যাব নমুনা অ্যাপ্লিকেশনটি ব্যবহার করব।

১. লঞ্চ এবং বেসলাইন

অ্যাপটি চালু করুন এবং স্মৃতিশক্তির একটি বেসলাইন রিডিং নিন:

adb shell am start -W -n com.android.memorylab/.MainActivity
adb shell dumpsys meminfo -s com.android.memorylab

আউটপুটে থাকা Stack এবং Native Heap সারিগুলো দেখুন। সেগুলো সম্ভবত ছোট হবে।

২. ১০০টি থ্রেড তৈরি করুন

'Create 100 Threads' বোতামটি ট্যাপ করুন। অ্যাপ্লিকেশনটি ১০০টি নতুন থ্রেড তৈরি করবে। স্ট্যাক মেমরি যেন প্রকৃতপক্ষে ফিজিক্যাল র‍্যামে পেজড হয় (যাতে আমরা আমাদের টুলগুলিতে এটি দেখতে পারি), তা নিশ্চিত করার জন্য, প্রতিটি থ্রেড ওয়েটিং শুরু করার আগে তার স্ট্যাকে একটি ছোট ১০কেবি অ্যারেতে মেমরি বরাদ্দ করে এবং লেখে।

থ্রেডগুলো সচল থাকা অবস্থায় meminfo কমান্ডটি আবার চালান:

adb shell dumpsys meminfo -s com.android.memorylab

ফলাফল:

নতুন আউটপুটটি আপনার বেসলাইনের সাথে তুলনা করুন। থ্রেডগুলো সক্রিয় থাকা অবস্থায় আপনি উল্লেখযোগ্য বৃদ্ধি লক্ষ্য করবেন:

  • Stack : এক মেগাবাইট বা তার বেশি বৃদ্ধি পেয়েছে। এটি ১০০টি থ্রেড স্ট্যাকের জন্য বরাদ্দকৃত ফিজিক্যাল পেজগুলোকে নির্দেশ করে (যার প্রতিটির আয়তন কমপক্ষে ১০ কিলোবাইট)।
  • Native Heap / Private Other : প্রতিটি থ্রেডের জন্য সিস্টেম দ্বারা বরাদ্দকৃত অভ্যন্তরীণ pthread স্ট্রাকচারগুলোর কারণে এটি বৃদ্ধি পায়।

পরিষ্কার করার জন্য, ‘Destroy All Threads’ বোতামটি ট্যাপ করুন।

৩. পারফেটোতে থ্রেড দেখা

সময়ের সাথে সাথে থ্রেডের জীবনচক্র এবং সংখ্যা ট্র্যাক করার জন্য পারফেটটো চমৎকার।

পারফেটটো UI-এর একটি স্ক্রিনশট, যেখানে মেমোরিল্যাব অ্যাপে সক্রিয় থ্রেডের সংখ্যা এবং থ্রেড শুরু ও বন্ধ হওয়ার সংখ্যাসহ একটি কাউন্টার ট্র্যাক দেখানো হচ্ছে।

থ্রেড বিশ্লেষণের জন্য পারফেটটোএসকিউএল

অ্যাপ্লিকেশনটি দ্বারা ঠিক কতগুলি থ্রেড তৈরি করা হয়েছিল তা গণনা করতে আপনি ট্রেসটি কোয়েরি করতে পারেন:

SELECT p.name AS process_name, COUNT(t.id) as thread_count
FROM thread t JOIN process p USING (upid)
WHERE p.name = 'com.android.memorylab' AND t.name LIKE 'LeakedThread-%';

স্ক্রিনশটে দেখানো কাউন্টারসহ একটি ডিবাগ ট্র্যাক তৈরি করতে এই ধরনের একটি কোয়েরি ব্যবহার করা যেতে পারে।


← অ্যাপ কোড | ↑ উপরে | এলাকা →