মেমরি রিক্লেম: এভিকশন ও সোয়াপ

আগের বিভাগে আমরা দেখেছি যে কার্নেল কীভাবে সিস্টেম-জুড়ে মেমরি ম্যানেজ করে। এই অধ্যায়ে, আমরা মেমরি কন্ট্রোল গ্রুপ (memcg) সম্পর্কে আরও বিস্তারিতভাবে আলোচনা করব, এটি হল এমন একটি মেকানিজম যা Android আলাদা আলাদা অ্যাপের জন্য মেমরির ব্যবহার পার্টিশন ও কন্ট্রোল করতে ব্যবহার করে।

memcg বোঝা অত্যন্ত গুরুত্বপূর্ণ কারণ এটি এমন একটি লেভেল যেখানে সিস্টেম মেমরি রিক্লেম করার জন্য নির্দিষ্ট অ্যাপকে টার্গেট করতে পারে বা সেগুলির উপর মেমরির সীমা সেট করতে পারে, যা অ্যাপের মেমরি ফুটপ্রিন্টের প্রোঅ্যাক্টিভ ম্যানেজমেন্টের সুবিধা দেয়।

মেমরি কন্ট্রোল গ্রুপ (memcg)

কন্ট্রোল গ্রুপ (cgroups) হল Linux কার্নেল ফিচার যা প্রসেসকে হায়ারার্কিক্যাল গ্রুপে সাজাতে এবং তাদের মধ্যে সিস্টেম রিসোর্স (যেমন CPU, মেমরি এবং I/O) ডিস্ট্রিবিউট করতে সাহায্য করে। memcg হল cgroup কন্ট্রোলার যা বিশেষভাবে মেমরির জন্য ব্যবহার করা হয়।

মূল memcg ধারণা

  • Memcg চার্জ: memcg-তে কোনও প্রসেস মেমরির একটি পৃষ্ঠা বরাদ্দ করলে (বেনামী বা ফাইল-ব্যাকড), সেই পৃষ্ঠাটি memcg-তে "চার্জ" করা হয়। একটি memcg-এর মোট চার্জ হল এর মধ্যে থাকা সমস্ত প্রসেস দ্বারা ব্যবহৃত সমস্ত পৃষ্ঠার যোগফল।
  • হায়ারার্কিক্যাল অ্যাকাউন্টিং: মেমরির ব্যবহার ট্রি-তে দেখানো হয়। চাইল্ড cgroup-এ চার্জ করা হলে তা পেরেন্ট cgroup-এর ব্যবহার হিসেবেও গণনা করা হয়।
  • মেমরির সীমা: প্রতিটি memcg-এর সীমা থাকতে পারে (যেমন memory.max বা memory.high) যা গ্লোবাল সিস্টেম মেমরি নির্বিশেষে, সীমা অতিক্রম করলে রিক্লেম বা এমনকি OOM কিলার ট্রিগার করে।
  • প্রতি-memcg রিক্লেম: যখন কোনও memcg তার সীমা অতিক্রম করে, বা যখন সিস্টেমের মেমরির প্রয়োজন হয়, তখন কার্নেল রিক্লেমের জন্য একটি নির্দিষ্ট memcg টার্গেট করতে পারে। এর অর্থ হল এর ফাইল পৃষ্ঠাগুলি খালি করা বা এর বেনামী পৃষ্ঠাগুলি ZRAM-এ সোয়্যাপ করা।

Android memcg হায়ারার্কি

অ্যাপ প্রসেস ম্যানেজ করার জন্য Android একটি নির্দিষ্ট ক্রম ব্যবহার করে। এই স্ট্রাকচার সিস্টেমকে বিভিন্ন ধরনের অ্যাপে (যেমন, ফোরগ্রাউন্ড বনাম ব্যাকগ্রাউন্ড) বিভিন্ন নীতি প্রয়োগ করার অনুমতি দেয়।

Android memcg হায়ারার্কি

  • /sys/fs/cgroup/apps/: সব Android অ্যাপ্লিকেশনের রুট।
  • uid_<UID>/: প্রতিটি অ্যাপের ব্যবহারকারীর আইডির জন্য একটি ডিরেক্টরি। একই অ্যাপ প্যাকেজের সব প্রসেস এই গ্রুপ শেয়ার করে।
  • pid_<PID>/: প্রতিটি স্বতন্ত্র প্রসেস এবং তার থেকে ফর্ক করা যেকোনও চাইল্ডের জন্য একটি ডিরেক্টরি। এটি একাধিক প্রসেস সহ অ্যাপের জন্য সূক্ষ্ম-দানাদার নিয়ন্ত্রণ এবং অ্যাকাউন্টিংয়ের অনুমতি দেয়।

হাতে-কলমে অনুশীলন: memcg এক্সপ্লোর করা

এই অনুশীলনে, আপনি MemoryLab-এর জন্য memcg ডিরেক্টরি খুঁজে পাবেন এবং রিয়েল-টাইমে এর মেমরি চার্জ পর্যবেক্ষণ করবেন।

১. MemoryLab লঞ্চ করুন

আপনার ডিভাইসে MemoryLab চলছে কিনা তা নিশ্চিত করুন।

২. MemoryLab-এর memcg খুঁজুন

প্রথমে, চালু থাকা MemoryLab অ্যাপের PID পান:

adb shell pidof com.android.memorylab
# Example output: 11672

এখন, এটির cgroup ডিরেক্টরি লোকেট করুন। আপনি এটি /proc/<PID>/cgroup-এ খুঁজে পাবেন:

adb shell cat /proc/11672/cgroup
# Example output: 0::/apps/uid_10274/pid_11672

cgroup v2-তে, 0::-এর পরে দেখানো পাথ /sys/fs/cgroup-এর সাথে সম্পর্কিত memcg হায়ারার্কি দেখায়। তাই সম্পূর্ণ পাথ হল /sys/fs/cgroup/apps/uid_10274/pid_11672/।

৩. memcg পরিসংখ্যান পড়ুন

সেই ডিরেক্টরিতে যান এবং মূল ফাইলগুলি দেখুন:

# Current memory usage (in bytes)
adb shell cat /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.current
# Example output:
# 1591324672

memory.current এই cgroup-এ বর্তমানে চার্জ করা মেমরির মোট পরিমাণ (বাইটে) দেখায়।

# Detailed statistics
adb shell cat /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.stat | head -n 10
# Example output:
# anon 1585098752
# file 741376
# kernel 5484544
# kernel_stack 393216
# pagetables 4583424
# sec_pagetables 0
# percpu 216
# sock 0
# vmalloc 4096
# shmem 20480

memory.stat একটি ব্রেকডাউন প্রদান করে: * anon: বেনামী মেমরির পরিমাণ (হিপস, স্ট্যাকস)। * file: ফাইল-ব্যাকড মেমরির পরিমাণ (পৃষ্ঠা ক্যাশে)। * swap: ZRAM-এ সোয়্যাপ আউট করা মেমরির পরিমাণ।

৪. পরিবর্তন লক্ষ্য করুন

  1. MemoryLab খুলুন।
  2. memory.current-এর ভ্যালু নোট করুন।
  3. জাভা মেমরি (১০ এমবি) বরাদ্দ করুন বিকল্পে কয়েকবার ট্যাপ করুন।
  4. memory.current আবার পড়ুন। প্রতিটি ট্যাপের জন্য এটি প্রায় ১০ এমবি করে বৃদ্ধি পাবে।
  5. বিটম্যাপ বরাদ্দ করুন বিকল্পে ট্যাপ করুন। anon-এর বৃদ্ধি দেখতে memory.stat চেক করুন।

memory.reclaim-এর মাধ্যমে প্রোঅ্যাক্টিভ রিক্লেম

memcg (v2)-এর একটি শক্তিশালী ফিচার হল memory.reclaim ফাইল। এই ফাইলে কোনও ভ্যালু লিখলে, কার্নেলকে অবিলম্বে এই memcg এবং এর অধীনে থাকা যেকোনও memcg থেকে সেই পরিমাণ মেমরি রিক্লেম করার চেষ্টা করার নির্দেশ দেয়।

Android কীভাবে memory.reclaim ব্যবহার করে

Android-এর CachedAppOptimizer এই ফিচার ব্যবহার করে যাতে অ্যাপ ফ্রিজ হয়ে যাওয়ার পরে সেগুলি থেকে সর্বাধিক মেমরি পুনরুদ্ধার করা যায়। Android অ্যাপ ফ্রিজার নিশ্চিত করে যে ক্যাশে করা অ্যাপগুলি না চলার সময় যতটা সম্ভব কম RAM ব্যবহার করে। কোনও অ্যাপ ব্যাকগ্রাউন্ডে চলে গেলে এবং ফ্রিজ হয়ে গেলে, সিস্টেম অ্যাপের বর্তমান মেমরির ব্যবহার তার memory.reclaim ফাইলে লিখে রাখে। এটি কার্নেলকে সম্ভাব্য সব ফাইল পৃষ্ঠা বের করে দিতে এবং সব বেনামী পৃষ্ঠা ZRAM-এ সোয়াপ করতে বাধ্য করে, যার ফলে অ্যাপের রেসিডেন্ট ফুটপ্রিন্ট কমে যায়।

আপনি memory.current পড়ে এবং memory.reclaim-এ আবার লিখে ম্যানুয়ালি একই "সর্বাধিক রিক্লেম" অর্জন করতে পারেন:

# Force reclaim of everything
adb shell "cat /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.current > /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.reclaim"

অনুশীলন: ফোর্স রিক্লেম ও ট্রেস

আমরা এখন কার্নেলকে MemoryLab থেকে মেমরি পুনরায় ব্যবহার করতে এবং Perfetto ট্রেসে অ্যাক্টিভিটি ক্যাপচার করতে বাধ্য করব।

  1. প্রস্তুত করুন: MemoryLab-এ কিছু অ্যালোকেশন (Java এবং বিটম্যাপ) আছে কিনা তা নিশ্চিত করুন।
  2. ট্রেসিং শুরু করুন: শিডিউলিং, রিক্লেম ও পৃষ্ঠা ক্যাশে ইভেন্ট ক্যাপচার করতে এই ইনলাইন ট্রেস কনফিগারেশন ব্যবহার করুন।

    # Use a config that captures scheduling, reclaim and page cache events
    adb shell perfetto -c - --txt -o /data/misc/perfetto-traces/reclaim.perfetto-trace <<EOF
    buffers: {
        size_kb: 131072
        fill_policy: RING_BUFFER
    }
    data_sources: {
        config {
            name: "linux.ftrace"
            ftrace_config {
                ftrace_events: "sched/sched_switch"
                ftrace_events: "sched/sched_wakeup"
                ftrace_events: "kmem/rss_stat"
                ftrace_events: "mm_filemap_add_to_page_cache"
                ftrace_events: "mm_filemap_delete_from_page_cache"
                ftrace_events: "vmscan/mm_vmscan_direct_reclaim_begin"
                ftrace_events: "vmscan/mm_vmscan_direct_reclaim_end"
                ftrace_events: "vmscan/mm_vmscan_memcg_reclaim_begin"
                ftrace_events: "vmscan/mm_vmscan_memcg_reclaim_end"
                symbolize_ksyms: true
            }
        }
    }
    data_sources: {
        config {
            name: "linux.process_stats"
            process_stats_config {
                scan_all_processes_on_start: true
            }
        }
    }
    EOF
    
  3. ট্রিগার প্রেসার ও রিক্লেম:

    • MemoryLab-এ, নেটিভ মেমরি বরাদ্দ করুন (১ জিবি) বিকল্পে ট্যাপ করুন। এর ফলে সিস্টেম-জুড়ে চাপ সৃষ্টি হবে।
    • আলাদা টার্মিনালে, ২০০ এমবি রিক্লেম করুন:

      adb shell "echo 200M > /sys/fs/cgroup/apps/uid_10274/pid_11672/memory.reclaim"
      
  4. Fault Back In: MemoryLab-এ ফিরে যান। Thrash Pagecache (Refault test) বিকল্পে ট্যাপ করুন।

  5. ট্রেস বন্ধ করুন: ট্রেস টার্মিনালে Ctrl+C প্রেস করুন।

Perfetto-তে রিক্লেম বিশ্লেষণ করা

ট্রেস খুললে, আপনি সিস্টেম-ওয়াইড এবং প্রতি-অ্যাপ রিক্লেম অ্যাকশনে দেখতে পাবেন:

Perfetto-তে ডাইরেক্ট ও memcg রিক্লেম দেখানো হচ্ছে

ট্রেসে নিম্নলিখিত বিষয়গুলি দেখুন:

  • kswapd: কার্নেল থ্রেড-এর অধীনে kswapd0 সার্চ করুন (উপরের স্ক্রিনশটে এটি ম্যানুয়ালি উপরে পিন করা হয়েছে)। সিস্টেম ফ্রি পৃষ্ঠা খুঁজে পেতে সমস্যায় পড়লে আপনি এটি জেগে উঠতে এবং চলতে (সবুজ স্লাইস) দেখতে পাবেন।
  • ডাইরেক্ট রিক্লেম: com.android.memorylab প্রসেস থ্রেড দেখুন। আপনি থ্রেডের শিডিউলিং ট্র্যাকের ঠিক নিচে বেগুনি রঙের ftrace ইভেন্ট স্লাইস (যেমন mm_vmscan_direct_reclaim_begin) দেখতে পাবেন। এর থেকে বোঝা যায় যে কার্নেল পৃষ্ঠা খালি করার জন্য অপেক্ষা করতে গিয়ে অ্যাপ থ্রেড নিজেই থেমে গেছে।
  • RSS এবং সোয়াপ কাউন্টার:
    • mem.rss.anon: আপনি বরাদ্দ করার বোতামে ট্যাপ করলে এটি বাড়ে।
    • mem.swap: kswapd এবং অ্যাপের নিজস্ব থ্রেড (সরাসরি রিক্লেম করার সাপেক্ষে) ZRAM-এ সেইসব বেনামী পৃষ্ঠা কম্প্রেস করার সাথে সাথে ক্রমাগত বৃদ্ধি পায়।
  • memcg রিক্লেম: আপনি ম্যানুয়াল রিক্লেম ট্রিগার করার মুহূর্তটি জুম-ইন করলে, mm_vmscan_memcg_reclaim ইভেন্টের সাথে rss.anon ও rss.file, উভয় ক্ষেত্রেই তীব্র পতন দেখতে পাবেন।

← সিস্টেম-ওয়াইড | ↑ উপরে | kswapd এবং lmkd ইন্টার‍্যাকশন →