মেমরি লিমিটার

Android 17 ও তার পরের যেকোনও ভার্সনে মেমরি লিমিটার থাকে, এটি একটি সিস্টেম পরিষেবা যা Linux cgroup v2 ব্যবহার করে অ্যাপ্লিকেশন প্রসেসের মেমরি ব্যবহার মনিটর ও সীমিত করে। মেমরি লিমিটার কোনও অ্যাপকে অতিরিক্ত সিস্টেম মেমরি ব্যবহার করতে দেয় না, এর ফলে সামগ্রিক মেমরি প্রেসার কমে যায় এবং গুরুত্বপূর্ণ ফোরগ্রাউন্ড ও ক্যাশ করা প্রসেসকে মেমরি কম থাকার কারণে বন্ধ করে দেওয়া হয় না।

পদ্ধতি

মেমরি লিমিটর, অ্যাক্টিভিটি ম্যানেজার সার্ভিসের (AMS) সাথে ইন্টিগ্রেট করে প্রসেস লাইফসাইকেল ইভেন্ট ও স্টেট পরিবর্তন ট্র্যাক করে। মেমরি লিমিটার Linux kernel cgroup v2 হায়ারার্কি ব্যবহার করে মেমরি সীমা প্রয়োগ করে।

মেমরি লিমিটারের জন্য, ডিভাইস কার্নেলকে অবশ্যই cgroup v2 এবং memory কন্ট্রোলার চালু করতে হবে। পরিষেবাটি বিশেষভাবে নিম্নলিখিত অ্যাট্রিবিউটের উপর নির্ভর করে:

memory.high
একটি সফট সীমা। সীমা পেরিয়ে গেলে, প্রসেস থ্রটল করা হয় এবং কার্নেল সেই প্রসেস থেকে প্রোঅ্যাক্টিভ পৃষ্ঠা রিক্লেম করার চেষ্টা করে।
memory.swap.max
প্রসেসটি ব্যবহার করতে পারে এমন সর্বাধিক সোয়াপ স্পেসের (যেমন, ZRAM) পরিমাণ সীমিত করে।

অ্যাপের উপর প্রভাব

যেসব অ্যাপ মেমরি সীমার মধ্যে কাজ করে, সেগুলির উপর মেমরি লিমিটারের কোনও প্রভাব পড়ে না।

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

অত্যন্ত গুরুতর পরিস্থিতিতে—যেমন, এমন একটি অনিয়ন্ত্রিত মেমরি লিক যেখানে সোয়াপ স্পেস শেষ হয়ে যাওয়ার পরে অ্যাপ অনামিকা মেমরি বরাদ্দ করা চালিয়ে যায়—অ্যাপ মেমরি বরাদ্দ করতে ব্যর্থ হয় এবং বন্ধ হয়ে যায়।

প্রসেস মনিটরিং

মেমরি লিমিটার ডিফল্ট হিসেবে অ্যাপ প্রসেস (UID >= 10000) মনিটর করে। প্রয়োজনীয় সিস্টেম স্টেবিলিটি বজায় রাখার জন্য কোর সিস্টেম প্রসেসকে ছাড় দেওয়া হয়।

মেমরি লিমিটার, প্রসেসের দৃশ্যমানতার অবস্থার উপর ভিত্তি করে মেমরি সীমা অ্যাসাইন করে:

  • দৃশ্যমান প্রসেস: ব্যবহারকারীর কাছে দৃশ্যমান UI হোস্ট করা প্রসেস (যেমন, বর্তমানে ফোকাস করা অ্যাক্টিভিটি বা অ্যাক্টিভ ইন্টার‍্যাকশন)। কারণ, UI দেখানোর জন্য রেন্ডারিং ও গ্রাফিক্স পাইপলাইনের জন্য আরও বড় ওয়ার্কিং সেট প্রয়োজন হয়, তাই দৃশ্যমান প্রসেসকে আরও বেশি মেমরি সীমা দেওয়া হয়।

  • দৃশ্যমান নয় এমন প্রসেস: UI না দেখিয়ে ব্যাকগ্রাউন্ডে কাজ করা প্রসেস (যেমন, ব্যাকগ্রাউন্ড পরিষেবা বা ব্রডকাস্ট রিসিভার)। যেহেতু এগুলি UI কম্পোনেন্ট রেন্ডার করে না, তাই এগুলি আরও বেশি বিধিনিষেধের অধীনে কাজ করে।

নিচের সারণীটি নির্দিষ্ট প্রসেস স্টেটকে মেমরি সীমা শ্রেণীবিভাগের সাথে ম্যাপ করে:

প্রসেস স্টেটমেমরির সীমা
PERSISTENTঅবাধ
PERSISTENT_UIঅবাধ
TOPদৃশ্যমান
BOUND_TOPদৃশ্যমান
FOREGROUND_SERVICEদেখা যাবে না
BOUND_FOREGROUND_SERVICEদেখা যাবে না
IMPORTANT_FOREGROUNDদৃশ্যমান
IMPORTANT_BACKGROUNDদেখা যাবে না
TRANSIENT_BACKGROUNDদেখা যাবে না
BACKUPদেখা যাবে না
SERVICEদেখা যাবে না
RECEIVERদেখা যাবে না
TOP_SLEEPINGদৃশ্যমান
HEAVY_WEIGHTদেখা যাবে না
HOMEদেখা যাবে না
LAST_ACTIVITYদেখা যাবে না
CACHED_ACTIVITYক্যাশেড
CACHED_ACTIVITY_CLIENTক্যাশেড
CACHED_RECENTক্যাশেড
CACHED_EMPTYক্যাশেড

ক্যাশে করা অবস্থায়, প্রসেস ফ্রিজ করা হয় এবং তারপরে যতটা সম্ভব রিক্লেইম করা হয়।

কোনও প্রসেসকে অ্যাসাইন করা memory.high সীমা অতিক্রম করলে, মেমরি লিমিটার ইভেন্টটি শনাক্ত করে এবং মেমরি প্রোফাইল ক্যাপচার করা বা statsd-এ অসঙ্গতি লগ করার মতো ডায়াগনস্টিক অ্যাকশন ট্রিগার করতে পারে।

কনফিগারেশন

Android 17 ও তার পরবর্তী যেকোনও ভার্সনে, মেমরি লিমিটারকে স্ট্যান্ডার্ড প্ল্যাটফর্ম কনফিগারেশন ফাইল ব্যবহার করে কনফিগার করা হয়। এটি সিস্টেম পার্টিশনে /system/etc/memory-limiter-config.xml থাকে।

XML ফর্ম্যাট

কনফিগারেশন ফাইলটি memory-limiter-config.xsd-এ সংজ্ঞায়িত স্কিমা অনুসরণ করে। ফাইলটি উপলভ্য মেমরি অনুসারে সাজানো একাধিক সীমা সেটকে সংজ্ঞায়িত করে; পরিষেবাটি ডিভাইসের উপলভ্য RAM-এর উপর ভিত্তি করে সর্বোচ্চ ম্যাচিং সীমা সেট বেছে নেয়। সব মেমরি ভ্যালু মেবিবাইটে (MiB) নির্দিষ্ট করা আছে।

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <!-- RAM boundaries account for MemTotal excluding carve-outs. -->
    <limitSet>
      <!-- Limits for 16GB RAM device [14336, 18432): 10G/5G/5G/5G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>18432</maximumAllowedMemTotal>
      <memVisible>10240</memVisible>
      <memNotVisible>5120</memNotVisible>
      <swapVisible>5120</swapVisible>
      <swapNotVisible>5120</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 12GB RAM device [9216, 14336): 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>9216</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>14336</maximumAllowedMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 8GB RAM device [6800, 9216): 5G/3G/3G/3G -->
      <minimumRequiredMemTotal>6800</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>9216</maximumAllowedMemTotal>
      <memVisible>5120</memVisible>
      <memNotVisible>3072</memNotVisible>
      <swapVisible>3072</swapVisible>
      <swapNotVisible>3072</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 6GB RAM device [4800, 6800): 4G/2G/2G/2G -->
      <minimumRequiredMemTotal>4800</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>6800</maximumAllowedMemTotal>
      <memVisible>4096</memVisible>
      <memNotVisible>2048</memNotVisible>
      <swapVisible>2048</swapVisible>
      <swapNotVisible>2048</swapNotVisible>
    </limitSet>
    <limitSet>
      <!-- Limits for 4GB RAM device [3200, 4800): 2G/1G/1G/1G -->
      <minimumRequiredMemTotal>3200</minimumRequiredMemTotal>
      <maximumAllowedMemTotal>4800</maximumAllowedMemTotal>
      <memVisible>2048</memVisible>
      <memNotVisible>1024</memNotVisible>
      <swapVisible>1024</swapVisible>
      <swapNotVisible>1024</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
কনফিগারেশন ভার্সন শনাক্তকারী ধনাত্মক পূর্ণসংখ্যা। এটি অবশ্যই 1 হতে হবে।
minimumRequiredMemTotal

এই সীমা সেট করার জন্য ন্যূনতম সিস্টেম MemTotal (MiB-তে, ইনক্লুসিভ ফ্লোর) প্রয়োজন। /proc/meminfo-এ কার্নেলের রিপোর্ট করা মোট উপলভ্য মেমরির সাথে পরিষেবা এটি মূল্যায়ন করে।

মেমরি কার্ভ-আউট ও বাউন্ডারি বোঝা: হার্ডওয়্যার ও ফার্মওয়্যার মেমরি কার্ভ-আউট বাদ দেওয়ার পরে অপারেটিং সিস্টেমের অ্যাক্সেসযোগ্য ফিজিক্যাল DRAM-কে কার্নেল MemTotal ভ্যালু রিফ্লেক্ট করে। কার্ভ-আউট GPU, বেসব্যান্ড মডেম, ক্যামেরা ISP, সুরক্ষিত এক্সিকিউশন এনভায়রনমেন্ট এবং হাইপারভাইজরের মতো বিশেষ হার্ডওয়্যার কম্পোনেন্টের জন্য RAM রিজার্ভ করে রাখে। সাধারণত এটি ৫০০ MiB থেকে ২ GiB-এর বেশি ফিজিক্যাল মেমরি ব্যবহার করে।

কারণ MemTotal ডিভাইসের বিজ্ঞাপিত ফিজিক্যাল DRAM-এর থেকে কম, minimumRequiredMemTotal এই কার্ভ-আউটের জন্য থ্রেশহোল্ডে মার্জিন অন্তর্ভুক্ত থাকে। যেমন, ১৬ GB ডিভাইসের জন্য টার্গেট করা কনফিগারেশনে 16384 (১৬ GiB)-এর পরিবর্তে 14336 (১৪ GiB)-এর ফ্লোর নির্দিষ্ট করা হয় এবং ১২ GB ডিভাইসের জন্য টায়ারে 9216 (৯ GiB)-এর ফ্লোর নির্দিষ্ট করা হয়। এর ফলে বোর্ড-লেভেল কার্ভ-আউট ভেরিয়েশন যাই হোক না কেন, প্রতিটি ডিভাইস যেন তার নির্ধারিত টিয়ারের সাথে ম্যাচ করে তা নিশ্চিত করা যায়।

maximumAllowedMemTotal

এই সীমা প্রয়োগ করার জন্য সর্বাধিক সিস্টেম MemTotal (MiB-তে, এক্সক্লুসিভ সিলিং) সেট করা আছে। MemTotal এই সর্বোচ্চ সীমার থেকে বেশি বা সমান হলে, সেট করা সীমা প্রযোজ্য হবে না। ১৮,৪৩২ MiB বা তার বেশি মেমরি আছে এমন ডিভাইস অথবা ৩,২০০ MiB-এর কম মেমরি আছে এমন ডিভাইসের ক্ষেত্রে, মেমরি লিমিটার কোনও সীমা প্রয়োগ করে না, ফলে প্রসেসগুলি আনকন্সট্রেন্ড থাকে।

memVisible

দৃশ্যমান প্রসেসে MiB-তে প্রয়োগ করা সফট মেমরি সীমা (memory.high)।

memNotVisible

MiB-তে প্রয়োগ করা সফট মেমরি সীমা (memory.high) দৃশ্যমান নয় এমন প্রসেসে প্রয়োগ করা হয়।

swapVisible

দৃশ্যমান প্রসেসে MiB-তে প্রয়োগ করা সোয়াপ স্পেসের সীমা (memory.swap.max)।

swapNotVisible

MiB-তে সোয়াপ স্পেসের সীমা (memory.swap.max) প্রয়োগ করা হয়, যা দেখা যায় না প্রসেস।

স্ট্যান্ডার্ড প্ল্যাটফর্ম সীমা

Android 17 ও তার পরের যেকোনও ভার্সনে, প্ল্যাটফর্ম [floor, ceiling) রেঞ্জ ইন্টারভ্যাল ব্যবহার করে সাধারণ ফিজিক্যাল RAM টিয়ার জুড়ে /system/etc/memory-limiter-config.xml-এ স্ট্যান্ডার্ড মেমরি ও সোয়াপ সীমা নির্দিষ্ট করে:

টার্গেট ফিজিক্যাল RAM MemTotal রেঞ্জ [floor, ceiling)
(minimumRequiredMemTotal,
maximumAllowedMemTotal)
দৃশ্যমান মেমরি সীমা
(memVisible)
দৃশ্যমান নয় এমন মেমরি সীমা
(memNotVisible)
দৃশ্যমান অদল-বদল সীমা
(swapVisible)
দেখা যাচ্ছে না এমন সোয়াপের সীমা
(swapNotVisible)
১৬ জিবি [14336, 18432) MiB ১০,২৪০ MiB (১০ GiB) ৫,১২০ MiB (৫ GiB) ৫,১২০ MiB (৫ GiB) ৫,১২০ MiB (৫ GiB)
১২ জিবি [9216, 14336) MiB ৮,১৯২ MiB (৮ GiB) ৪,০৯৬ MiB (৪ GiB) ৪,০৯৬ MiB (৪ GiB) ৪,০৯৬ MiB (৪ GiB)
৮ জিবি [6800, 9216) MiB ৫,১২০ MiB (৫ GiB) ৩,০৭২ MiB (৩ GiB) ৩,০৭২ MiB (৩ GiB) ৩,০৭২ MiB (৩ GiB)
৬ জিবি [4800, 6800) MiB ৪,০৯৬ MiB (৪ GiB) ২,০৪৮ মেবিবাইট (২ গিবিবাইট) ২,০৪৮ MiB (২ GiB) ২,০৪৮ MiB (২ GiB)
৪ জিবি [3200, 4800) মেবিবাইট ২,০৪৮ মেবিবাইট (২ গিবিবাইট) ১,০২৪ MiB (১ GiB) ১,০২৪ মেবিবাইট (১ গিবিবাইট) ১,০২৪ MiB (১ GiB)

মেমরি সীমা সংক্রান্ত নীতি

মেমরি লিমিটার কনফিগারেশন নিম্নলিখিত প্ল্যাটফর্ম নীতির উপর ভিত্তি করে ডিজাইন করা হয়েছে:

  • ইকোসিস্টেমের সামঞ্জস্য ও অ্যাপের উপযুক্ততা: ডিভাইস জুড়ে সামঞ্জস্যপূর্ণ মেমরি সীমা Android ইকোসিস্টেম জুড়ে অ্যাপের পারফর্ম্যান্সের ব্যাপারে আগে থেকে অনুমান করতে সাহায্য করে। অ্যাপগুলি স্ট্যান্ডার্ড মেমরি প্রত্যাশা অনুযায়ী ডেভেলপ ও পরীক্ষা করা হয়; একই ধরনের প্ল্যাটফর্ম সীমা বজায় রাখলে অপ্রত্যাশিত থ্রটলিং বা সময়ের আগে বন্ধ হয়ে যাওয়া এড়ানো যায়।

  • আনুপাতিক রিসোর্স অ্যালোকেশন: প্ল্যাটফর্মের সীমা ফিজিক্যাল RAM ক্যাপাসিটি অনুসারে ক্যালিব্রেট করা হয়:

    • দৃশ্যমান প্রসেস: অ্যাক্টিভ UI, কম্পোজিশন ও রেন্ডারিং ওয়ার্কলোডকে সাপোর্ট করার জন্য মোট ফিজিক্যাল RAM-এর প্রায় ১/২ থেকে ২/৩ অংশ বরাদ্দ করা হয়।
    • দৃশ্যমান নয় এমন প্রসেস: ব্যাকগ্রাউন্ড টাস্কের জন্য মোট ফিজিক্যাল RAM-এর আনুমানিক ১/৪ থেকে ১/৩ ভাগ বরাদ্দ করা হয়।
  • সর্বত্র প্রযোজ্য: ডিভাইসে (UID >= 10000) আগে থেকে ইনস্টল করা সিস্টেম ও OEM অ্যাপ সহ সমস্ত অ্যাপ্লিকেশন প্রসেসে সীমা সমানভাবে প্রযোজ্য হয়। মেমরি লিমিটার নির্দিষ্ট অ্যাপকে ছাড় দেওয়ার জন্য শ্বেততালিকা ব্যবহার করে না, এর ফলে সব অ্যাপ জুড়ে মেমরি ম্যানেজমেন্ট ন্যায্যভাবে করা যায়।

  • রানটাইম কোয়েরি API-এর অনুপস্থিতি: Android 17 এবং তার পরবর্তী ভার্সনে, অ্যাপ রান টাইমে প্রোগ্রাম্যাটিক্যালি তার অ্যাসাইন করা মেমরি সীমা কোয়েরি করতে পারে না। সাধারণ ব্যবহারের সময় যাতে ভালভাবে আচরণ করা অ্যাপ কোনও সীমাবদ্ধতা ছাড়াই কাজ করতে পারে, সেই জন্য স্ট্যান্ডার্ড প্ল্যাটফর্মের সীমাগুলি যথেষ্ট মার্জিন সহ নির্ধারণ করা হয়।

  • কার্নেল রিক্লেম ও সোয়াপ ডায়নামিক্স: কোনও অ্যাপ প্রসেস তার memory.high সীমার কাছাকাছি পৌঁছালে, Linux কার্নেল মেমরি রিক্লেমকে নির্দিষ্টভাবে সেই প্রসেস cgroup-এ নির্দেশ করে। এর মধ্যে রয়েছে ইনঅ্যাক্টিভ ফাইল-ব্যাকড পেজ বাদ দেওয়া এবং ZRAM-এ কোল্ড অ্যানোনিমাস পেজ অদল-বদল করা, গ্লোবাল মেমরি প্রেসার না চাপিয়েই সিস্টেমের ফ্লুইডিটি বজায় রাখা।

শেল কমান্ড

am memory-limiter কমান্ডের সাহায্যে ডেভেলপার ও সিস্টেম ইন্টিগ্রেটররা ডেভেলপমেন্ট, টেস্টিং ও ডিবাগিংয়ের জন্য রান টাইমে পরিষেবার সাথে ইন্টার‍্যাক্ট করতে পারেন:

am memory-limiter <SUB-COMMAND>

স্ট্যাটাস

status সাব-কমান্ড, মেমরি লিমিটারের অপারেশনাল স্ট্যাটাস ও অ্যাক্টিভ মেট্রিক সম্পর্কে রিপোর্ট করে:

adb shell am memory-limiter status

নিচে আউটপুটের উদাহরণ দেওয়া হল:

Memory limiter
  enabled                  monitoring=true          ignored=none
  visibleMem=1948MB        visibleSwap=974MB
  notVisibleMem=974MB      notVisibleSwap=487MB
  started=36               watched=36               watch-failed=0
  events=0                 processes=36             process-hwm=36

আউটপুটের মূল ফিল্ডের মধ্যে এগুলি অন্তর্ভুক্ত:

monitoring
মেমরি লিমিটার অ্যাক্টিভভাবে প্রসেস দেখছে কিনা তা নির্দেশ করে।
visibleMem ও notVisibleMem
প্রতিটি দৃশ্যমানতা অবস্থার জন্য বর্তমানে প্রয়োগ করা গণনা করা পরম মেমরি সীমা (memory.high)।
visibleSwap ও notVisibleSwap
প্রতিটি দৃশ্যমানতা স্টেটের জন্য বর্তমানে এনফোর্স করা গণনা করা মোট অদল-বদল করার সীমা (memory.swap.max)।
events
কোনও প্রসেস যতবার তার জন্য নির্ধারিত সীমা অতিক্রম করেছে।
processes
মনিটর করা প্রসেসের বর্তমান সংখ্যা।

এড়িয়ে যান

ignore সাব-কমান্ড সাময়িকভাবে কোনও নির্দিষ্ট UID বা সমস্ত প্রসেসকে মেমরি সীমিত করা থেকে বাদ দেয়। এটি পারফর্ম্যান্স বেঞ্চমার্কিং, স্ট্রেস টেস্টিং বা মেমরি বিহেভিয়ার ডায়াগনসিস করার জন্য উপযোগী:

# Ignore a specific UID
adb shell am memory-limiter ignore 10087
# Ignore all processes (temporarily disables limiting)
adb shell am memory-limiter ignore all
# Resume normal limiting operation
adb shell am memory-limiter ignore none

ম্যানুয়াল

manual সাব-কমান্ড, প্রসেস আইডি (PID) অনুযায়ী নির্দিষ্ট প্রসেসের জন্য গণনা করা সীমা ওভাররাইড করে এবং বাইটে কাস্টম অ্যাবসোলিউট ভ্যালু সেট করে। মানটি অবশ্যই একটি পূর্ণসংখ্যা হতে হবে, তবে MiB বোঝাতে MB প্রত্যয় বা GiB বোঝাতে GB প্রত্যয় অন্তর্ভুক্ত থাকতে পারে:

# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1073741824
# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1024MB
# Set a 1GiB limit for PID 1234
adb shell am memory-limiter manual 1234 1GB
# Remove the manual override for PID 1234
adb shell am memory-limiter manual 1234 none

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

ম্যানুয়াল ওভাররাইড ফিজিক্যাল সিস্টেমের সীমা অতিক্রম করতে পারে না।