সিস্টেম মেমরি বাজেট

Android 17 এবং তার পরবর্তী ভার্সনে, প্ল্যাটফর্মটি দুটি পরিপূরক Linux cgroup v2 মেকানিজম ব্যবহার করে সিস্টেম প্রসেস মেমরি পরিচালনা করে যা সাধারণ অ্যাপ্লিকেশন মেমরি লিমিটারের পাশাপাশি কাজ করে:

  • সিস্টেম ডেমন প্রোটেকশন ফ্লোর (SystemMemoryBudgetManager-এর সাথে memory.min): সেল্ফ-টিউনিং cgroup v2 memory.min রিজার্ভেশন (প্রতিটি ডেমনের সেটেল করা রেসিডেন্ট ওয়ার্কিং সেটের ৯০% হিসেবে সেট করা এবং মোট ফিজিক্যাল RAM-এর ১০% হিসেবে গ্লোবালি ক্যাপ করা) মেমরি প্রেসারের অধীনে ক্রিটিক্যাল ইন্টার‍্যাক্টিভ ডেমন ও শেল প্রসেস (system_server, surfaceflinger, গ্রাফিক্স composer HAL, audioserver, cameraserver, netd, SystemUI এবং হোম লঞ্চার) সুরক্ষিত করে, স্ট্যাটিক PinnerService mlock ফাইল পিন করার বিকল্প হিসেবে কাজ করে।
  • সিস্টেম অ্যাপ মেমরি সিলিং (memory.high সহ <memory-budget>): ওয়ার্কলোড-ক্যালিব্রেট করা cgroup v2 memory.high সফট লিমিট (সাধারণত ৩০ এমবি থেকে ১৯০ এমবি) পারসিস্টেন্ট ও ব্যাকগ্রাউন্ড সিস্টেম অ্যাপের (Bluetooth, Nfc, CalendarProvider, Traceur, MediaProvider, :PhotoPicker, NetworkStack, AppSearch এবং TeleService) জন্য ম্যানিফেস্ট ফাইলে ঘোষণা করা হয়েছে যা গ্লোবাল মেমরি প্রেসার হওয়ার আগে প্রোঅ্যাক্টিভভাবে কোল্ড ফাইল পেজ ক্যাশে ও পোস্ট-বার্স্ট অ্যানোনিমাস হিপ রিক্লেম করে।

নিচের সারণীতে দুটি মেকানিজমের তুলনা করা হয়েছে:

আকার সিস্টেম ডেমন প্রোটেকশন ফ্লোর সিস্টেম অ্যাপের মেমরি সিলিং
প্ল্যাটফর্ম পরিষেবা SystemMemoryBudgetManager MemoryLimiter
Cgroup v2 কন্ট্রোল memory.min হার্ড প্রোটেকশন ফ্লোর memory.high সফ্ট রিক্লেম সিলিং
টার্গেট প্রসেস system_server, surfaceflinger, composer HAL, audioserver, cameraserver, netd, SystemUI এবং Home অ্যাপের মতো লেটেন্সি-ক্রিটিক্যাল ইন্টার‍্যাক্টিভ ডেমন ও শেল UI পারসিস্টেন্ট ও হেডলেস সিস্টেম অ্যাপ, কন্টেন্ট প্রোভাইডার ও ব্যাকগ্রাউন্ড পরিষেবা (যেমন Bluetooth, Nfc, MediaProvider, NetworkStack, AppSearch ও TeleService)
সাইজিং মডেল রান টাইমে সেল্ফ-টিউনিং (সেটেল করা ওয়ার্কিং সেটের ৯০%, বিশ্বব্যাপী মোট RAM-এর ১০% ক্যাপ করা) এবং প্রতি-ডিভাইস টিউনিং টেবিল শূন্য RAM টিয়ার, প্রসেস স্টেট ও ডিসপ্লে পিক্সেল কাউন্ট দ্বারা ক্যালিব্রেট করা ডিক্লারেটিভ <memory-budget> ম্যানিফেস্ট XML অ্যাট্রিবিউট
প্রাথমিক সুবিধা স্ট্যাটিক PinnerService mlock ফাইলের তালিকা পরিবর্তন করার সময় মেমরির উপর চাপ পড়লে ইন্টার‍্যাক্টিভ UI জ্যাঙ্ক ও ওয়েকআপ স্টল প্রতিরোধ করে ফোরগ্রাউন্ড ও ক্যাশে করা অ্যাপের জন্য আরও ফিজিক্যাল RAM খালি করতে, কোল্ড ওয়ান-টাইম ফাইল ক্যাশে ও পোস্ট-বার্স্ট হিপ ক্রমাগত খালি করে

<memory-budget> সিনট্যাক্স, XML অ্যাট্রিবিউট, রানটাইম API এবং OS মেমরি অ্যাকাউন্টিং সম্পর্কে আরও তথ্যের জন্য, অ্যাপ মেমরি বাজেট সেট করুন এবং Android মেমরি বোঝা এবং সমস্যা সমাধান করা দেখুন।

SystemMemoryBudgetManager-এর মাধ্যমে গুরুত্বপূর্ণ ইন্টার‍্যাক্টিভ ডেমন সুরক্ষিত রাখুন

SystemMemoryBudgetManager মেমরি প্রেসারের সময় ফিজিক্যাল RAM-এ রেসিডেন্ট ব্যবহারকারীর ইন্টার‍্যাক্টিভ পাথে সরাসরি থাকা প্রসেসকে রেখে দেয়। mlock (যেমন PinnerService, config_defaultPinnerServiceFiles ও config_pinnerHomePinBytes-এর জন্য করে) ব্যবহার করে মেমরিতে APK, ODEX ও VDEX ফাইলের স্ট্যাটিক তালিকা পিন করার পরিবর্তে, SystemMemoryBudgetManager নিম্নলিখিত প্রসেসে ডায়নামিক cgroup v2 memory.min ফ্লোর অ্যাসাইন করে:

  • কোর সিস্টেম স্লাইস (/sys/fs/cgroup/system): system_server, surfaceflinger, গ্রাফিক্স composer HAL, audioserver, cameraserver এবং netd, সাথে ফর্ম-ফ্যাক্টর-নির্দিষ্ট নেটিভ সিস্টেম বা config_systemMemoryBudgetAdditionalSystemProcesses-এ তালিকাভুক্ত ভেন্ডর ডেমন (যেমন, XR ডিভাইসে android.hardware.perceptionhost এবং auracamerahal)।
  • ইন্টার‍্যাক্টিভ অ্যাপ স্লাইস (/sys/fs/cgroup/apps): কনফিগার করা SystemUI প্যাকেজের (config_systemUi) প্রধান প্রসেস এবং বর্তমান ব্যবহারকারীর হোম রোলের প্রধান প্রসেস।

config_systemUi-এর পাশাপাশি হোম রোল হোল্ডারকে সুরক্ষিত রাখলে সব ফর্ম ফ্যাক্টর জুড়ে কভারেজ নিশ্চিত করা যায়। যেসব ফর্ম ফ্যাক্টরে config_systemUi হল একটি লাইটওয়েট কম্প্যাটিবিলিটি প্যাকেজ (যেমন Wear OS, যেখানে ওয়াচফেস, বিজ্ঞপ্তি এবং টাইল Home অ্যাপের মধ্যে চলে), সেখানে ব্যবহারকারী নিজে ইন্টার‌্যাক্ট করতে পারেন এমন শেল এখনও সম্পূর্ণ ওয়ার্কিং-সেট সুরক্ষা পায়। Home ইনটেন্ট config_systemUi প্যাকেজে সমাধান করলে, প্রসেসটি একবার সুরক্ষিত করা হয়। প্রতিটি প্যাকেজের (processName == packageName) শুধুমাত্র প্রধান প্রসেস সুরক্ষা ফ্লোর পায়, তাই সহায়ক সাবপ্রসেস (যেমন :screenshot) সুরক্ষা বাজেট খরচ করে না।

সেল্ফ-টিউনিং নীতি এবং তিন-লেভেল cgroup ডেলিগেশন

কারণ ইন্টার‍্যাক্টিভ ডেমন-এর ওয়ার্কিং সেট ফর্ম ফ্যাক্টর ও RAM-এর ক্ষমতার উপর নির্ভর করে ব্যাপকভাবে পরিবর্তিত হয় (যেমন, SystemUI স্মার্টওয়াচে প্রায় ৪৫ এমবি, ৬ জিবি ফোনে ৬০ এমবি এবং ১৬ জিবি ফোনে ১৮০ এমবি ব্যবহার করে), তাই ডিভাইস প্রতি স্ট্যাটিক লুকআপ টেবিল ভঙ্গুর হয়। পরিবর্তে, SystemMemoryBudgetManager তিনটি ধ্রুবক ব্যবহার করে প্রতিটি প্রসেসের নিজস্ব রেসিডেন্ট ফুটপ্রিন্ট থেকে সরাসরি ফ্লোর বের করে:

নীতি সংক্রান্ত প্যারামিটার ডিফল্ট মান আচরণ
প্রসেস প্রতি ফ্লোর সেটেল করা memory.current-এর ৯০% ম্যাপ না করা ফাইল ক্যাশের থেকে কম এটি বেনামী হিপ, স্ল্যাব এবং হট ম্যাপ করা কোডকে সুরক্ষিত রাখে এবং সবচেয়ে কোল্ড ১০% টেইল রিক্লেম করার জন্য ছেড়ে দেয় যাতে জেনুইন কোল্ড পেজ এখনও এভিক্ট করা যায়। ৯০% অনুপাত প্রয়োগ করার আগে আনম্যাপ করা ফাইল ক্যাশে (memory.stat থেকে max(0, file - shmem - file_mapped)) বিয়োগ করা হয় যাতে বুট প্যাকেজ-স্ক্যান ক্যাশে বা এককালীন অ্যাসেট রিড ফ্লোরকে স্ফীত না করে।
গ্লোবাল RAM ক্যাপ মোট RAM-এর ১০% (config_systemMemoryBudgetLowKb) PinnerService config_pinnerMaxPinnedMemoryPercentage গার্ডরেলের সাথে ম্যাচ করে। ৯০% ফ্লোরের যোগফল যদি MemTotal-এর ১০% ছাড়িয়ে যায়, তাহলে প্রতিটি ফ্লোর একই ফ্যাক্টর দ্বারা আনুপাতিকভাবে কমানো হয়।
রিফ্রেশ ক্যাডেন্স শুরু হওয়ার ১, ৪, ১৬ ও ৬৪ সেকেন্ড পরে, তারপর প্রতি ৩০ মিনিট অন্তর অন্তর একটি জ্যামিতিক সেটেল সিরিজ প্রতিটি ডেমন-এর পোস্ট-স্টার্টআপ ওয়ার্কিং সেটে কনভার্জ করে, প্রতিটি ডিভাইসের ওয়ার্ম-আপ বিলম্ব হার্ডকোড না করেই। এছাড়াও, ৩০-মিনিটের স্টেডি-স্টেট রিফ্রেশ ডিভাইসের লাইফটাইম জুড়ে ওয়ার্কিং-সেটের ধীরে ধীরে বৃদ্ধি এবং সংকোচন ট্র্যাক করে।

Linux cgroup v2 মেমরি কন্ট্রোলারে (mm/memcontrol.c:effective_protection), লিফ cgroup-এর কার্যকর memory.min সুরক্ষা, তার পেরেন্ট ও পূর্বপুরুষ cgroup-এ কনফিগার করা memory.min দ্বারা সীমাবদ্ধ। uid_<uid>/memory.min, 0 হলে শুধুমাত্র লিফ pid_<pid> ডিরেক্টরিতে memory.min সেট করার ফলে কার্যকরী সুরক্ষা শূন্য হয়ে যায়। অন্যদিকে, শুধুমাত্র উপরের /sys/fs/cgroup/system স্লাইসে ফ্ল্যাট memory.min সেট করলে, দাবি না করা সুরক্ষা সমস্ত চাইল্ড UID এবং প্রসেস জুড়ে সমানুপাতিকভাবে (memory_recursiveprot) বিতরণ করা হয়, যা ডায়াগনস্টিক বা সেকেন্ডারি প্রসেস শেয়ারিং uid_1000 (android.uid.system)-কে surfaceflinger এবং audioserver থেকে সুরক্ষা সরিয়ে নিতে দেয়।

প্রতি ডেমন আইসোলেশন প্রদান করতে, SystemMemoryBudgetManager প্রতিটি রিফ্রেশে cgroup v2 হায়ারার্কির তিনটি লেভেল জুড়ে সুরক্ষা লেখে, যেমনটি চিত্র ১-এ দেখানো হয়েছে:

  1. লিফ প্রসেস নোড (pid_<pid>/memory.min): প্রসেসের (স্কেল করা) ৯০% ওয়ার্কিং-সেট ফ্লোরে সেট করা হয়েছে।
  2. UID নোড (uid_<uid>/memory.min): এটি ম্যানেজ করা pid_* লিফ ফ্লোরের সঠিক যোগফলে সেট করুন, যাতে সেই UID শেয়ার করা আনম্যানেজড প্রসেস (যেমন অন্যান্য AID_SYSTEM ডেমন বা sharedUserId="android.uid.system" প্যাকেজ) memory.min = 0 এবং সুরক্ষার দাবি করতে পারে না।
  3. টপ-লেভেল স্লাইস (/sys/fs/cgroup/system/memory.min এবং /sys/fs/cgroup/apps/memory.min): এর uid_* চাইল্ডের সঠিক যোগফলে সেট করুন। ম্যানেজ করা নোডে থাকা যেকোনও পুরনো memory.low ভ্যালু মুছে 0 করা হয়, এবং আগের রিফ্রেশে ম্যানেজ করা যেকোনও uid_* ডিরেক্টরি (যেমন ব্যবহারকারী লঞ্চার পরিবর্তন করার পরে আগের হোম লঞ্চার) রিসেট করে 0 করা হয়।

/sys/fs/cgroup/system এবং /sys/fs/cgroup/apps জুড়ে তিন-লেভেল cgroup v2 memory.min সুরক্ষা হায়ারার্কি, UID এবং স্লাইস নোডে যোগ করা লিফ প্রসেস ফ্লোর দেখাচ্ছে, যেখানে অসুরক্ষিত সিবলিং প্রসেস শূন্যে থাকে

ছবি ১. cgroup স্লাইস জুড়ে তিন-লেভেল সুরক্ষা ফ্লোর ডেলিগেশন।

MGLRU কার্নেলে memory.low-এর পরিবর্তে কেন memory.min ব্যবহার করা হয়

মাল্টি-জেনারেশনাল LRU (MGLRU, Android 6.6 এবং নতুন কার্নেলে ডিফল্ট পৃষ্ঠা রিক্লেম ইঞ্জিন)-এর অধীনে, memory.low এবং memory.min mm/vmscan.c:shrink_one-এ আলাদাভাবে আচরণ করে:

  • memory.low (সিঙ্গেল-পাস ডিফারাল): একটি cgroup যার ব্যবহার memory.low-এর নিচে, সেটি memcg LRU (MEMCG_LRU_TAIL)-এর শেষে রোটেট করা হয় এবং একটি সিঙ্গেল রিক্লেম পাসের জন্য স্কিপ করা হয়। মেমরি প্রেসার বজায় থাকার কারণে পরবর্তী পাসে, কার্নেল cgroup সম্পূর্ণভাবে রিক্লেম করে এবং একটি MEMCG_LOW ইভেন্ট লগ করে। ফিজিক্যাল ডিভাইসের স্ট্রেস টেস্টে, ফিজিক্যাল RAM-এর ৮৫% পর্যন্ত অজ্ঞাত মেমরি হগ বৃদ্ধি পাওয়ার সাথে, memory.low স্মার্টওয়াচে SystemUI ~৪৫ এমবি থেকে ~৫ থেকে ১০ এমবি পর্যন্ত এবং audioserver ১৬ জিবি ফোল্ডেবল ডিভাইসে ~১৪ এমবি ফ্লোরের বিপরীতে ১৫ এমবি থেকে ২ এমবি পর্যন্ত ড্রপ করার অনুমতি দেয়।
  • memory.min (হার্ড প্রোটেকশন ফ্লোর): গ্লোবাল রিক্লেম এমন cgroup-কে এড়িয়ে যায় যার ব্যবহার memory.min-এর নিচে। ছবি ২-এ যেমন দেখানো হয়েছে, একই ৮৫% RAM প্রেসার ওয়ার্কলোডের অধীনে, memory.min প্রতিটি ডেমন থেকে শুধুমাত্র সবচেয়ে কোল্ড ১০% টেল শেড করে এবং SystemUI, surfaceflinger ও audioserver-কে তাদের ৯০% ফ্লোরে ধরে রাখে। এর ফলে, কোনও অ্যানোনিমাস রিফল্ট হয় না এবং lmkd প্রসেস টার্মিনেশনও বৃদ্ধি পায় না।

memory.min, PinnerService mlock পিনিংয়ের সুরক্ষার সাথে ম্যাচ করে এমন হার্ড ফিজিক্যাল রিজার্ভেশন প্রদান করে, যেটি এটি রিপ্লেস করে। এর সুবিধা হল, কার্নেল LRU (স্ট্যাটিক ফাইল তালিকার পরিবর্তে) বেছে নেয় যে কোন হট কোড, হিপ এবং গ্রাফিক্স পৃষ্ঠা রেসিডেন্ট হিসেবে থাকবে।

সিস্টেম মেমরির চাপ ফিজিক্যাল RAM-এর ৪০% থেকে ৯৫% পর্যন্ত বৃদ্ধি পাওয়ার সাথে সাথে ডেমন রেসিডেন্ট মেমরির তুলনা, যা দেখায় যে memory.min তার ৯০% ফ্লোরে ধরে রাখে এবং memory.low একটি একক MGLRU ডিফারাল পাসের পরে ভেঙে পড়ে

ছবি ২. মেমরি প্রেসার বাড়ার সময় ডেমন ওয়ার্কিং-সেট রিটেনশন।

বুট প্রি-ওয়ার্মিং এবং পোস্ট-বুট আনম্যাপ করা ফাইল ক্যাশে রিক্লেম

config_defaultPinnerServiceFiles-এর PinnerService স্থায়ী mlock পরিবর্তন করতে দুটি বুট-টাইম আচরণকে সমন্বয় করতে হয়:

  • এক-শট ব্যাকগ্রাউন্ড বুট প্রিওয়ার্মিং (PinnerService): PinnerService mlock পৃষ্ঠা ক্যাশে ওয়ার্ম না করে এড়িয়ে গেলে, SystemUI শুরু হওয়ার (OnBootPhase_550) সময়, ~৯৫ এমবি SystemUI APK, ODEX ও VDEX ডিস্ক রিড, সিঙ্ক্রোনাস বুট পাথে শিফট করে, যার ফলে বুট সম্পূর্ণ হতে ৩০০ থেকে ৪৫০ মি.সে. বেশি সময় লাগে। madvise(MADV_WILLNEED) কল করা যথেষ্ট নয় কারণ কার্নেলে force_page_cache_ra একটি MADV_WILLNEED কলকে একটি রিডঅ্যাহেড উইন্ডোতে (সাধারণত ১২৮ কেবি থেকে ২ এমবি) ক্ল্যাম্প করে। পরিবর্তে, যখন SystemMemoryBudgetManager.shouldSkipDefaultSystemPinning অ্যাক্টিভ থাকে, PinnerService onStart চলাকালীন ব্যাকগ্রাউন্ড থ্রেডে config_defaultPinnerServiceFiles-এর প্রতিটি ফাইল ম্যাপ করে, Os.mlock-এর সাহায্যে সিঙ্ক্রোনাসভাবে ফাইলটি পৃষ্ঠা ক্যাশেতে পপুলেট করে এবং অবিলম্বে Os.munlock, munmap ও close কল করে। এটি ফাস্ট বুট টাইমিং বজায় রাখে এবং স্থায়ীভাবে লক করা বাইট শূন্য করে দেয় যাতে কোল্ড স্টার্টআপ পৃষ্ঠা পরে সরিয়ে দেওয়া যায়।
  • system_server বুট প্যাকেজ-স্ক্যান ক্যাশে বাদ দেওয়া ও রিক্লেম করা: বুট করার সময়, PackageManagerService ইনস্টল করা APK স্ক্যান করে, ১.৫ থেকে ২.৫ জিবি কোল্ড আনম্যাপ করা ফাইল পৃষ্ঠা ক্যাশে system_server cgroup-এ চার্জ করা হয়। system_server-এর memory.min গণনায় অন্তর্ভুক্ত থাকলে, কোল্ড বুট ক্যাশে ১০% গ্লোবাল RAM ক্যাপকে স্যাচুরেট করে এবং surfaceflinger, SystemUI ও audioserver-এর প্রোটেকশন ফ্লোরকে আনুপাতিকভাবে কমিয়ে দেয়। ক্যাপ স্টারভেশন প্রতিরোধ করতে, SystemMemoryBudgetManager system_server-এর জন্য memory.stat পড়ে, ম্যাপ না করা ফাইল ক্যাশে max(0, file - shmem - file_mapped) হিসেবে গণনা করে এবং ৯০% ফ্লোর গণনা করার আগে memory.current থেকে ম্যাপ না করা ক্যাশে বিয়োগ করে, যেমনটি চিত্র ৩-এ দেখানো হয়েছে। এছাড়াও, PHASE_BOOT_COMPLETED-এর ১০ সেকেন্ড পরে, ম্যানেজার Linux 6.2 এবং আরও নতুন কার্নেলে system_server-এর memory.reclaim নোডে <unmapped_file> swappiness=0-এর একটি ওয়ান-শট রাইট পারফর্ম করে যাতে বেনামী হিপ সোয়্যাপ না করে বা ম্যাপ করা DEX এবং কোড পৃষ্ঠাগুলি এড়িয়ে না গিয়ে কোল্ড প্যাকেজ-স্ক্যান ক্যাশে সক্রিয়ভাবে এড়িয়ে যাওয়া যায়। পুরনো কার্নেলে (যেমন android14-6.1) যা EINVAL-এর সাথে swappiness=0 প্রত্যাখ্যান করে, ম্যানেজার memory.reclaim রাইট এড়িয়ে যায়, অযোগ্য রিক্লেম রাইটে ফিরে যাওয়ার পরিবর্তে যা বুট করার সময় বেনামী হিপ সোয়্যাপ আউট করবে।

বুট করার পরে system_server মেমরির টাইমলাইন, যা ১, ৪, ১৬ এবং ৬৪ সেকেন্ডে জ্যামিতিক সেটেল রিফ্রেশ দেখায়, ৯০% memory.min ফ্লোর থেকে আনম্যাপ করা বুট প্যাকেজ-স্ক্যান ক্যাশে বাদ দেওয়া এবং swappiness=0 সহ ওয়ান-শট memory.reclaim

ছবি ৩. বুট করার পরে প্রোটেকশন ফ্লোর কনভারজেন্স ও ক্যাশে রিক্লেম।

কার্নেল সংক্রান্ত প্রয়োজনীয়তা এবং ডিভাইস কনফিগারেশন ওভারলে

SystemMemoryBudgetManager, Linux কার্নেলে mem_cgroup_calculate_protection-এর উপর নির্ভর করে নেস্ট করা cgroup জুড়ে memory.min প্রোপাগেট করার জন্য। Android কমন কার্নেল android15-6.6 এবং android16-6.12-এ ডিফল্ট হিসেবে সম্পূর্ণ MGLRU নেস্টেড সুরক্ষা সহায়তা অন্তর্ভুক্ত থাকে। MGLRU চালু থাকা android14-6.1 ভার্সনে চলা ডিভাইসের ক্ষেত্রে mm/vmscan.c ও mm/memcontrol.c-এ তিনটি আপস্ট্রিম ব্যাকপোর্ট প্রয়োজন যাতে খালি ইন্টারমিডিয়েট স্লাইস ও UID cgroups লিফ প্রসেস cgroups-এ সুরক্ষা প্রোপাগেট করে:

  • 30d77b7eef01 (mm/mglru: fix ineffective protection calculation)
  • 8aa420617918 (mm/mglru: respect min_ttl_ms with memcgs)
  • adb8213014b2 (mm: memcg: fix stale protection of reclaim target memcg)

OEM নিম্নলিখিত ফ্রেমওয়ার্ক রিসোর্স ওভারলে ব্যবহার করে SystemMemoryBudgetManager কাস্টমাইজ বা বন্ধ করতে পারে:

  • config_systemMemoryBudgetLowKb (পূর্ণসংখ্যা, কেবি): 0 (ডিফল্ট) মোট ফিজিক্যাল RAM-এর ১০% এ সব memory.min ফ্লোরের যোগফল ক্যাপ করে। পজিটিভ ভ্যালু কেবিতে একটি নির্দিষ্ট সীমা সেট করে এবং নেগেটিভ ভ্যালু ডিভাইসে SystemMemoryBudgetManager বন্ধ করে দেয় (লেগেসি PinnerService স্ট্যাটিক mlock পিন করা বজায় রাখে)।
  • config_systemMemoryBudgetHighKb (পূর্ণসংখ্যা, কেবি): 0 (ডিফল্ট) /sys/fs/cgroup/system/memory.high-এ max বাকি আছে। একটি পজিটিভ ভ্যালু একটি টপ স্লাইস memory.high সিলিং সেট করে (অবশ্যই ফ্লোর ক্যাপের চেয়ে বেশি বা সমান হতে হবে)।
  • config_systemMemoryBudgetAdditionalSystemProcesses (স্ট্রিং-অ্যারে): /sys/fs/cgroup/system-এ অতিরিক্ত লেটেন্সি-ক্রিটিক্যাল নেটিভ সিস্টেম বা ভেন্ডর ডেমন প্রসেসের নাম তালিকাভুক্ত করে (10000-এর অধীনে সিস্টেম ও ভেন্ডর UID-এর জন্য /proc/<pid>/cmdline-এ /proc/<pid>/comm বা argv[0]-এর বেসনেমের সাথে মিলিয়ে দেখা হয়) যাতে ডিফল্ট ছয়টি সিস্টেম ডেমনের পাশাপাশি 90% memory.min ফ্লোর সহ সুরক্ষিত করা যায়। init.rc-এ memory.min সেট করার পরিবর্তে এই ওভারলে ব্যবহার করুন কারণ SystemMemoryBudgetManager, uid_<uid>/memory.min-কে এর ম্যানেজ করা লিফ প্রসেসের যোগফল হিসেবে আবার গণনা করে এবং প্রতিটি রিফ্রেশে ম্যানেজ না করা uid_* নোড মুছে দেয়। যেমন, একটি XR ডিভাইস নিম্নলিখিত ওভারলে সহ এর স্পেশাল ট্র্যাকিং এবং ক্যামেরা HAL ডেমন সুরক্ষিত করতে পারে:

    <string-array translatable="false" name="config_systemMemoryBudgetAdditionalSystemProcesses">
        <item>android.hardware.perceptionhost</item>
        <item>auracamerahal</item>
    </string-array>
    
  • config_systemUi (string): প্ল্যাটফর্ম SystemUI অ্যাপের প্যাকেজের নাম, MATCH_SYSTEM_ONLY-এর সাথে সমাধান করা হয়েছে।

ডিভাইসে অ্যাক্টিভ SystemMemoryBudgetManager ফ্লোর ও cgroup নোড পরীক্ষা করতে, রান করুন:

# Inspect policy state, resolved PIDs, and applied floors in dumpsys meminfo
adb shell dumpsys meminfo | sed -n '/System Memory Budgets/,$p'
# Inspect raw cgroup v2 memory.min nodes across the system and apps slices
adb shell head -n 1 \
  /sys/fs/cgroup/system/memory.min \
  /sys/fs/cgroup/system/uid_*/memory.min \
  /sys/fs/cgroup/system/uid_*/pid_*/memory.min \
  /sys/fs/cgroup/apps/memory.min \
  /sys/fs/cgroup/apps/uid_*/memory.min \
  /sys/fs/cgroup/apps/uid_*/pid_*/memory.min

মেমরি বাজেটের সাথে পারসিস্টেন্ট ও ব্যাকগ্রাউন্ড সিস্টেম অ্যাপ বাউন্ড করুন

SystemMemoryBudgetManager ইন্টার‍্যাক্টিভ ডেমনকে memory.min ফ্লোর ব্যবহার করে রিক্লেম করা থেকে রক্ষা করে, অন্যান্য অনেক সিস্টেম অ্যাপ এবং প্রিভিলেজড প্ল্যাটফর্ম পরিষেবা PERSISTENT প্রসেস, বাউন্ড ফোরগ্রাউন্ড পরিষেবা বা ঘনঘন কোয়েরি করা কন্টেন্ট প্রোভাইডার হিসেবে দীর্ঘ সময় ধরে ব্যাকগ্রাউন্ডে চলে। মেমরির নির্দিষ্ট সীমা না থাকলে, এই প্রসেসগুলি মাল্টি-গিগাবাইট মেমরি লিমিট সীমায় (যেমন, দৃশ্যমান অ্যাপের জন্য ৪ জিবি থেকে ১০ জিবি এবং ব্যাকগ্রাউন্ড অ্যাপের জন্য ২ জিবি থেকে ৫ জিবি) না পৌঁছানো পর্যন্ত বা গ্লোবাল মেমরি প্রেসার সিস্টেম-ব্যাপী kswapd এবং লো-মেমরি কিলার (lmkd) অ্যাক্টিভিটি ট্রিগার না করা পর্যন্ত সীমাবদ্ধ থাকে না।

কোনও বাধা না থাকলে, ব্যাকগ্রাউন্ড সিস্টেম প্রসেস প্রায়ই প্রচুর পরিমাণে কোল্ড মেমরি জমা করে যা তাদের অ্যাক্টিভ ওয়ার্কিং সেটের অংশ নয়:

  • আনবাউন্ডেড ফাইল পৃষ্ঠা ক্যাশে: যেসব পরিষেবা মিডিয়া ইন্ডেক্স করে, ডেটাবেস সার্চ করে অথবা ক্যালেন্ডার ও প্রোভাইডার টেবিল (যেমন AppSearch, MediaProvider ও CalendarProvider) সিঙ্ক করে, সেগুলি ডিস্কে বড় ফাইলের মাধ্যমে ম্যাপ বা স্ট্রিম করে। cgroup memory.high সিলিং ছাড়া, একবার রিড করা থেকে ক্লিন ফাইল-ব্যাক করা পৃষ্ঠাগুলি প্রসেস cgroup-এ অনির্দিষ্টকালের জন্য চার্জ করা থাকে, যা শত শত মেগাবাইট ফিজিক্যাল RAM ব্যবহার করে।
  • পোস্ট-বার্স্ট অ্যানোনিমাস হিপ রিটেনশন: যেসব পরিষেবাতে ক্ষণস্থায়ী অ্যাক্টিভিটি স্পাইক দেখা যায়, যেমন Bluetooth অডিও এবং BLE ডিসকভারি বার্স্ট, NetworkStack ক্যাপটিভ-পোর্টাল TLS যাচাইকরণ বা ব্যাকগ্রাউন্ডে ট্রানজিশন করা UI হেল্পার, বার্স্ট সম্পূর্ণ হওয়ার অনেক পরেও কোল্ড অ্যানোনিমাস হিপ পেজ ধরে রাখতে পারে।

সিস্টেম অ্যাপে ক্যালিব্রেট করা <memory-budget> ডিক্লারেশন (memory.high সফট লিমিট, সাধারণত ৩০ এমবি থেকে ১৯০ এমবি) প্রয়োগ করলে দুটি প্রাথমিক সুবিধা পাওয়া যায়:

  • প্রোঅ্যাক্টিভ, লোকালাইজড পেজ রিক্লেম: কোনও সিস্টেম প্রসেস তার কনফিগার করা memory.high বাজেট অতিক্রম করলে, Linux কার্নেল পেজ রিক্লেমকে নির্দিষ্টভাবে সেই cgroup-এ নির্দেশ করে, প্রথমে কোল্ড ফাইল-ব্যাকড পেজগুলি সরিয়ে দেয় এবং গ্লোবাল ডিভাইস মেমরি প্রেসারের জন্য অপেক্ষা না করে নিষ্ক্রিয় বেনামী পৃষ্ঠাগুলিকে ZRAM-এ কম্প্রেস করে।
  • ফোরগ্রাউন্ড অ্যাপ ও ক্যাশে করা অ্যাপ পুলের জন্য আরও RAM উপলভ্য: সবসময় চালু থাকা সিস্টেম পরিষেবা জুড়ে বাউন্ডিং কোল্ড ফাইল ক্যাশে, ডিভাইস জুড়ে দশ থেকে শত শত মেগাবাইট ফিজিক্যাল RAM রিক্লেম করে, UI জ্যাঙ্ক কমায়, ক্যামেরা লঞ্চ করার চাপ কমায় এবং ক্যাশে করা অবস্থায় আরও ব্যবহারকারীর অ্যাপ চালু রাখে।

সিস্টেম অ্যাপ মেমরি বাজেট কনফিগার করুন

সিস্টেম অ্যাপ সাধারণ অ্যাপের মতোই <memory-budget> ম্যানিফেস্ট সিনট্যাক্স, প্রসেস-স্টেট ক্যাসকেডিং, ডিসপ্লে-ঘনত্ব স্কেলিং এবং শেষ-ম্যাচিং-ক্লজ রেজোলিউশন নিয়ম ব্যবহার করে। অ্যাট্রিবিউটের সম্পূর্ণ তালিকা দেখতে, XML অ্যাট্রিবিউট রেফারেন্স দেখুন।

OEM সরাসরি সিস্টেম অ্যাপের AndroidManifest.xml-এর মধ্যে <memory-budget> এলিমেন্ট ঘোষণা করতে পারে অথবা Android.bp-এ additional_manifests প্রপার্টি ব্যবহার করে আলাদা XML ফাইল থেকে সেগুলি মার্জ করতে পারে। কনভেনশন অনুযায়ী, AOSP স্ট্যান্ডঅ্যালোন *-budget.xml ফাইলে (কোর প্ল্যাটফর্ম প্যাকেজের জন্য frameworks/base/core/memory_budgets/-এ অথবা packages/modules/NetworkStack/memory_budgets/, packages/modules/AppSearch/apk/ ও packages/services/Telephony/-এর মতো স্বতন্ত্র মডিউলের পাশাপাশি) রেফারেন্স সিস্টেম অ্যাপ বাজেট স্টোর করে এবং সেগুলিকে additional_manifests-এর সাথে অ্যাটাচ করে:

android_app {
    name: "TeleService",
    manifest: "AndroidManifest.xml",
    additional_manifests: ["Telephony-budget.xml"],
    // ...
}

প্যাকেজ-লেভেল (UID) বনাম প্রসেস-লেভেল (PID) স্কোপিং

আপনি প্যাকেজ-লেভেল বেসলাইন বাজেট (<application>) নাকি মাল্টি-প্রসেস বাজেট (<processes><process>) ঘোষণা করছেন তার উপর নির্ভর করে কার্নেল UID cgroup লেভেলে (/sys/fs/cgroup/uid_<uid>/memory.high) নাকি প্রতি-PID cgroup লেভেলে (/sys/fs/cgroup/uid_<uid>/pid_<pid>/memory.high) memory.high এনফোর্স করবে, যেমনটি চিত্র ৪-এ দেখানো হয়েছে:

  • প্যাকেজ-লেভেল (<application>) বাজেট: APK যখন নিজস্ব ডেডিকেটেড UID-এর অধীনে একটি প্রসেস রান করে তখন ব্যবহার করুন (যেমন, Bluetooth, Nfc, NetworkStack, CalendarProvider, Traceur বা AppSearch)।
  • প্রসেস-লেভেল (<processes><process>) বাজেট: APK শেয়ার করার সময় ব্যবহার করুন android:sharedUserId (যেমন android.uid.phone UID 1001 সহ অথবা android.uid.system UID 1000 সহ) অন্যান্য সিস্টেম প্যাকেজের সাথে যাতে অন্যান্য প্রসেস যা UID শেয়ার করছে তা একসাথে থ্রটল না হয় অথবা যখন একটি APK একাধিক প্রসেস চালায় আলাদা মেমরি রোলের সাথে (যেমন, ব্যাকগ্রাউন্ড MediaProvider ডেমন এবং :PhotoPicker UI সাবপ্রসেস)।

Cgroup v2 হায়ারার্কি, ডেডিকেটেড UID-এর জন্য UID-লেভেল memory.high এনফোর্সমেন্টের সাথে শেয়ার করা সিস্টেম UID ও মাল্টি-প্রসেস APK-এর জন্য per-PID memory.high এনফোর্সমেন্টের তুলনা করে

ছবি ৪. UID-লেভেল বনাম PID-লেভেল মেমরি সিলিং।

নিচের উদাহরণে MediaProvider-budget.xml দেখানো হয়েছে, যা RAM-টিয়ার্ড বাজেটকে ডিফল্ট MediaProvider প্রসেস (<process>) এবং ডিসপ্লে-স্কেল করা বাজেটকে :PhotoPicker UI প্রসেসে স্কোপ করে। প্রতিটি android:maxDeviceRamMb অ্যাট্রিবিউট সেইসব ডিভাইসের সাথে ম্যাচ করে যেগুলির মোট ফিজিক্যাল RAM (MemTotal) নির্দিষ্ট করা MB থ্রেশহোল্ডের সমান বা তার কম (অথবা বাদ দেওয়া হলে যেকোনও RAM ক্যাপাসিটির ক্ষেত্রে প্রযোজ্য)। ক্লজগুলি আনকনস্ট্রেইন্ড ডিফল্ট থেকে শুরু করে সবচেয়ে ছোট maxDeviceRamMb থ্রেশহোল্ড পর্যন্ত সাজানো থাকে যাতে লাস্ট-ম্যাচিং-ক্লজ রেজোলিউশন নিয়ম সবচেয়ে কঠোর প্রযোজ্য টিয়ার বেছে নেয়:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.android.providers.media.module">
    <uses-sdk android:targetSdkVersion="10000" />
    <application>
        <processes>
            <process>
                <memory-budget
                    android:maxMb="85" />
                <memory-budget
                    android:maxMb="75"
                    android:maxDeviceRamMb="12288" />
                <memory-budget
                    android:maxMb="60"
                    android:maxDeviceRamMb="8192" />
            </process>
            <process android:process=":PhotoPicker">
                <memory-budget
                    android:maxMb="85"
                    android:additionalBytesPerDisplayPixel="25" />
            </process>
        </processes>
    </application>
</manifest>

Google Pixel ডিভাইসে কীভাবে AOSP রেফারেন্স বাজেট ক্যালিব্রেট করা হয়েছে

AOSP-তে রেফারেন্স সিস্টেম অ্যাপ মেমরি বাজেট, ৬ জিবি থেকে ১৬ জিবি ফিজিক্যাল RAM (৬ জিবি, ৮ জিবি, ১২ জিবি ও ১৬ জিবি ফোন, ফোল্ডেবল ও ট্যাবলেট সহ) এবং ~১.২ এমপি (৭২০×১৬০০) থেকে ~৪.৫ এমপি (২০৭৬×২১৫২) পর্যন্ত ডিসপ্লে রেজোলিউশন সহ Google Pixel ডিভাইস জুড়ে ক্যালিব্রেট করা হয়েছে।

ক্যালিব্রেশন দুটি পরিপূরক ডেটা সোর্সকে একত্রিত করেছে: ফ্লিট-ওয়াইড cgroup v2 ফিল্ড টেলিমেট্রি এবং ক্রিটিকাল ইউজার জার্নি (CUJ) জুড়ে নিয়ন্ত্রিত ফিজিক্যাল-ডিভাইস memory.high সুইপ।

ফ্লিট-ওয়াইড cgroup v2 টেলিমেট্রি বিশ্লেষণ

ডিভাইস ফ্লিট জুড়ে পর্যায়ক্রমিক cgroup v2 স্ন্যাপশট সংগ্রহ করা হয়েছে এবং ফিজিক্যাল RAM টিয়ার (≤৮ জিবি, ১২ জিবি এবং ≥১৬ জিবি) এবং প্রসেস স্টেট বাকেট (foreground, perceptible, background এবং cached) দ্বারা স্লাইস করা হয়েছে। পরিসংখ্যানগত বিশ্লেষণকে ছয়টি নীতি নির্দেশ করেছে:

  • memory.current-কে ওয়ার্কিং সেট বনাম রিক্লেম করা যায় এমন ফাইল ক্যাশেতে ডিকম্পোজ করুন: যেহেতু memory.high রেসিডেন্ট cgroup চার্জ (memory.current) নিয়ন্ত্রণ করে, তাই প্রতিটি স্ন্যাপশট memory.stat ব্যবহার করে অ্যানোনিমাস হিপ (anon), সোয়্যাপ করা অ্যানোনিমাস পৃষ্ঠা (swap) এবং ফাইল-ব্যাকড পৃষ্ঠা ক্যাশেতে (file) ডিকম্পোজ করা হয়েছে, যেমনটি চিত্র ৫-এ দেখানো হয়েছে। মোট ইনকমপ্রেসিবল অ্যানোনিমাস ডিমান্ড (P99-এ anon + swap) বাজেটের জন্য ন্যূনতম ওয়ার্কিং-সেট ফ্লোর প্রতিষ্ঠা করে যাতে প্রসেসটি ZRAM শেষ হওয়ার ঝুঁকি না নেয়, যেখানে memory.current P99 এবং anon + swap P99-এর মধ্যে একটি বড় ব্যবধান ফাইল পেজ ক্যাশে নির্দেশ করে যা memory.high রিক্লেম করতে পারে, যদি ক্যাশে আনম্যাপ করা এবং কোল্ড হয়।
  • মেমরির জন্য অ্যাকাউন্ট যা memory.high রিক্লেম করতে পারে না: সব ফাইল এবং শেয়ার করা মেমরি কোল্ড ক্যাশে নয়। লক করা পৃষ্ঠা (memory.stat-এ unevictable, যেমন mlock-এর সাথে লক করা শেয়ার করা মেমরি অথবা ভার্চুয়াল মেশিনের লক করা গেস্ট RAM যার হোস্ট প্রসেস অ্যাপের cgroup-এ চার্জ করা হয়) বাজেটের অধীনে একটি হার্ড ফ্লোর সেট করে এবং ম্যাপ করা পৃষ্ঠা (file_mapped) প্রায়ই অ্যাক্টিভ ওয়ার্কিং সেটের অংশ হয়। ফাইল মেমরি রিক্লেম করা যাবে কিনা তা বিবেচনা করার আগে unevictable, shmem এবং file_mapped চেক করুন। যেমন, প্রায় ১০০ এমবি AppSearch মেমরি লক করা আছে এবং তা খালি করা যাবে না, তাই এর বাজেট সেই ফ্লোর এবং তার হট হোস্ট ওয়ার্কিং সেট কভার করে, সাথে লক করা অঞ্চলের আকার বাড়ানোর জন্য হেডরুমও থাকে।
  • আইডল-স্টেট ডাইলুশন ফিল্টার আউট করা: কন্টেন্ট প্রোভাইডার (CalendarProvider) এবং অন-ডিমান্ড ডেভেলপার টুল (Traceur) ফিল্ড স্ন্যাপশটের ৭০% থেকে ৯৯.৯% ~১ এমবি থেকে ৩ এমবিতে আইডল অবস্থায় কাটায়। সব স্ন্যাপশট জুড়ে র-পার্সেন্টাইল গণনা করলে P95 এবং P99-এর অনুমান মারাত্মকভাবে কমে যায়। পরিবর্তে, পার্সেন্টাইল এবং আস্থা ব্যবধানগুলি আনডিলিউটেড অ্যাক্টিভ স্ন্যাপশটগুলির উপর গণনা করা হয়েছিল (CACHED স্ন্যাপশট এবং নিষ্ক্রিয় বেসলাইন স্ন্যাপশটগুলি ফিল্টার করে)।
  • ডিভাইস-ক্লাস্টার করা আস্থা ব্যবধান ব্যবহার করুন: কারণ একটি ডিভাইস সময়ের সাথে সাথে অনেক পিরিয়ডিক স্ন্যাপশট প্রদান করে, স্ন্যাপশটকে স্বতন্ত্র স্যাম্পেল হিসেবে বিবেচনা করলে টেল অনিশ্চয়তা কম করে দেখানো হয়। সব P95 এবং P99 ওয়ার্কিং সেট অনুমান রক্ষণশীল ডিভাইস-ক্লাস্টার্ড ৯৫% কনফিডেন্স ইন্টারভ্যাল (কার্যকর স্যাম্পেল সাইজ হিসেবে স্বতন্ত্র ডিভাইস সংখ্যা N_dev ব্যবহার করে) ব্যবহার করে মূল্যায়ন করা হয়েছে।
  • memory.peak-এর সাথে ট্রানজিয়েন্ট বার্স্টের জন্য অ্যাকাউন্ট: পর্যায়ক্রমিক স্যাম্পলিং স্বল্পস্থায়ী, উচ্চ-অ্যালোকেশন বার্স্ট মিস করতে পারে (যেমন NetworkStack ক্যাপটিভ-পোর্টাল TLS যাচাইকরণ এবং সমবর্তী DNS প্রোব, অথবা Bluetooth A2DP এবং BLE ইনিশিয়ালাইজেশন)। বার্স্টি পরিষেবার জন্য, বাজেট এমনভাবে নির্ধারণ করা হয়েছে যাতে RAM টিয়ার জুড়ে লাইফটাইম কার্নেল memory.peak-এর ৯০ থেকে ৯৫ পার্সেন্টাইল হাই-ওয়াটার মার্ক কভার করা যায়।
  • RAM টিয়ার যে RAM-কে প্রতিফলিত করে, ডিভাইসের জেনারেশনকে নয়, তা কনফার্ম করুন: নতুন ডিভাইসে সাধারণত বেশি RAM ও বেশি ফিচার থাকে, তাই RAM টিয়ারের সাথে সাথে যে ওয়ার্কিং সেট বৃদ্ধি পায়, তা আসলে ফিচারের সাথে সাথে বৃদ্ধি পেতে পারে। maxDeviceRamMb টিয়ার যোগ করার আগে, ডিভাইস মডেল অনুযায়ী ডেটা স্লাইস করুন। যেমন, com.android.phone একই জেনারেশনের ১২ জিবি ও ১৬ জিবি ফোনে একই P99 anon + swap (~৮৫ থেকে ৯০ এমবি) ব্যবহার করে, যেখানে পুরনো ১২ জিবি ফোল্ডেবল ৪০ এমবি ব্যবহার করে। তাই এর বাজেটে কোনও RAM টিয়ার ছাড়াই একটি একক মান ব্যবহার করা হয়, যাতে কম-RAM-এর ডিভাইস যা নতুন টেলিফোনি ফিচার সহ শিপ করা হয়, তার বাজেট কম না হয়।

সময়ের সাথে সাথে cgroup মেমরিকে ইনকম্প্রেসিবল অ্যানোনিমাস ওয়ার্কিং সেট, অ্যাক্টিভ ফাইল ক্যাশে উইন্ডো এবং কোল্ড ওয়ান-টাইম ফাইল ক্যাশেতে ডিকম্পোজ করা হয় যা memory.high-এর বাইরে রিক্লেম করা হয়

ছবি ৫. ওয়ার্কিং সেট বনাম রিক্লেম করা যায় এমন ফাইল ক্যাশে।

ফিজিক্যাল-ডিভাইস CUJ এবং ডিসপ্লে-স্কেলিং সুইপ

টেলিমেট্রি-প্রাপ্ত বাজেট যাচাই করতে এবং ডিসপ্লে-অনুপাতিক বাজেট (যেমন :PhotoPicker) ও রাজ্য-নির্দিষ্ট ব্যাকগ্রাউন্ড বাজেট (যেমন Traceur) ক্যালিব্রেট করতে, ৬ জিবি থেকে ১৬ জিবি RAM-এর ফিজিক্যাল ডিভাইসে লাইভ memory.high সুইপ চালানো হয়েছে:

  • জিরো-রিফল্ট নি খুঁজে পাওয়া: এন্ড-টু-এন্ড CUJ (যেমন ফাস্ট ফটো গ্রিড ফ্লিংগিং, অ্যালবাম ব্রাউজিং, ফুল-স্ক্রিন হাই-রেজোলিউশন ফটো ও ভিডিও প্রিভিউ সোয়াইপ করা এবং ট্রেস রেকর্ডিং ও সেভ করা) চালানোর সময়, memory.high cgroup memory.stat কাউন্টার (workingset_refault_anon, workingset_refault_file, pgscan এবং pgsteal) ও memory.events (high) পরিমাপ করার সময় স্টেপ ডাউন করা হয়েছে। চিত্র ৬-এ যেমন দেখানো হয়েছে, অপ্টিমাল বাজেট ঠিক জিরো-রিফল্ট নি-এর উপরে থাকে। জিরো-রিফল্ট নি হল সেই থ্রেশহোল্ড যেখানে কার্নেল কোল্ড ওয়ান-টাইম ফাইল ক্যাশে (pgsteal > 0) অ্যাক্টিভ ওয়ার্কিং-সেট থ্রেশিং (workingset_refault == 0) ট্রিগার না করেই রিক্লেম করে।
  • রেজোলিউশন জুড়ে ডিসপ্লে-পিক্সেল স্কেলিং যাচাই করা: ~১.২ এমপি (৭২০×১৬০০) থেকে ~৪.৫ এমপি (২০৭৬×২১৫২ আনফোল্ড করা ইনার ডিসপ্লে) পর্যন্ত চারটি ফিজিক্যাল ও এমুলেট করা ডিসপ্লে রেজোলিউশন জুড়ে :PhotoPicker পরীক্ষা করে কনফার্ম করা হয়েছে যে এর অ্যাক্টিভ Glide ও ViewPager2 বিটম্যাপ ওয়ার্কিং সেট ডিসপ্লে পিক্সেল কাউন্টের সাথে লিনিয়ারলি স্কেল করে। নন-ডিসপ্লে বেসলাইনও ডিভাইস অনুযায়ী আলাদা হয়: প্রায় একই পিক্সেল কাউন্টে, জিরো-রিফল্ট নি ১৬ জিবি ফোল্ডেবল ডিভাইসের আউটার ডিসপ্লেতে প্রায় ১৪০ এমবি ছিল, যেখানে ৬ জিবি ফোনে এটি ছিল ১১০ থেকে ১২৫ এমবি। ৮৫ এমবি বেসলাইন প্লাস প্রতি ডিসপ্লে পিক্সেলে ২৫ বাইট (android:maxMb="85" এবং android:additionalBytesPerDisplayPixel="25") পরিমাপ করা নী-এর উপরে থাকে প্রতিটি পরীক্ষিত ডিসপ্লেতে (~১১০ এমবি HD+-এ, ~১৪৫ এমবি FHD+-এ এবং ~১৯০ এমবি আনফোল্ড করা ডিসপ্লেতে)।
  • ব্যাকগ্রাউন্ড স্ট্যাটাসে ART গার্বেজ কালেকশন যাচাই করা: cgroup v2-তে, Zygote-শেয়ার করা boot.art এবং ফ্রেমওয়ার্ক ইমেজ পৃষ্ঠাগুলি Zygote-এর cgroup-এ চার্জ করা থাকে এবং ART কনকারেন্ট মার্ক-কম্প্যাক্ট (CMC) গার্বেজ কালেকশনের সময় একটি ইমিউন স্পেস হিসাবে বিবেচিত হয়। স্ট্রেস টেস্টিং থেকে কনফার্ম করা হয়েছে যে, সিস্টেম UI অ্যাপ background-এ ট্রানজিশন করার সময়, memory.high-কে টাইট করা (যেমন, Traceur-এ ৩০ এমবি-তে) GC থ্র্যাশিং বা সোয়াপ অ্যাক্টিভিটি না ঘটিয়েই প্রাইভেট হিপ ও পৃষ্ঠা ক্যাশে পরিষ্কারভাবে বাউন্ড করে।

CUJ চলাকালীন memory.high নিচের দিকে নামার সাথে সাথে কোল্ড ক্যাশে রিক্লেম (pgsteal) এবং ওয়ার্কিং-সেট থ্র্যাশিং (workingset_refault)-এর প্লট, জিরো-রিফল্ট নি এবং টার্গেট বাজেট হাইলাইট করা হয়েছে

ছবি ৬. CUJ-এর সময় জিরো-রিফল্ট নি খুঁজে দেখা।

AOSP রেফারেন্স সিস্টেম অ্যাপ বাজেটের সারাংশ

নিম্নলিখিত সারণীতে RAM টিয়ার এবং প্রসেস স্টেট জুড়ে AOSP-তে ক্যালিব্রেট করা রেফারেন্স বাজেটের সারসংক্ষেপ দেওয়া হয়েছে:

সিস্টেম প্যাকেজ বা প্রসেস সুযোগ ≤৮ জিবি র‌্যাম ১২ জিবি র‌্যাম ≥১৬ জিবি র‌্যাম প্রাথমিক ক্যালিব্রেশন ড্রাইভার
com.android.bluetooth UID (<application>) ৮০ এমবি ৯৫ এমবি ১১০ এমবি P90 লাইফটাইম memory.peak বার্স্ট (~৭৫ থেকে ১১০ এমবি) এবং >২x P99 অ্যাক্টিভ memory.current কভার করে।
com.android.nfc UID (<application>) ৫০ এমবি ৬০ এমবি ৬০ এমবি কোল্ড ফাইল ক্যাশে ট্রিম করার সময় অ্যাক্টিভ হোস্ট কার্ড ইমুলেশন P99 (সর্বাধিক ~৫০ এমবি) এবং P90 থেকে P95 memory.peak কভার করে।
com.android.providers.calendar UID (<application>) ৭০ এমবি ডিফল্ট (ফোরগ্রাউন্ড)
৫০ এমবি perceptible ও background
অ্যাক্টিভ ওয়ার্কিং সেট RAM টিয়ার জুড়ে অপরিবর্তিত থাকে। সিঙ্ক করার সময় SQLite পৃষ্ঠা ক্যাশে ট্রিম করার সময় ব্যাকগ্রাউন্ড বাজেট রিমাইন্ডার অ্যালার্মের জন্য বেনামী হেডরুম রাখে।
com.android.traceur UID (<application>) ৮৫ এমবি ডিফল্ট (ফোরগ্রাউন্ড ও লক্ষণীয়)
৩০ এমবি background
অ্যাক্টিভ ট্রেস রেকর্ডিং ও এক্সপোর্ট (TraceService) করার সময় সম্পূর্ণ ৮৫ এমবি হেডরুম বজায় রাখে, যেখানে আইডল ও ব্রডকাস্ট স্টেট ৩০ এমবিতে ক্যাপ করে।
com.android.providers.media.module (প্রধান) PID (<process>) ৬০ এমবি ৭৫ এমবি ৮৫ এমবি কোল্ড SQLite এবং থাম্বনেল ফাইল ক্যাশে রিক্লেম করার সময় P99 anon + swap-এর উপর ~১০ থেকে ৩০ এমবি হেডরুম প্রদান করে।
com.android.providers.media.module:PhotoPicker PID (<process>) ৮৫ এমবি + ২৫ বাইট প্রতি পিক্সেল
(HD+-এ ~১১০ এমবি, FHD+-এ ~১৪৫ এমবি, ~৪.৫ এমপি ফোল্ডে ~১৯০ এমবি)
Glide বিটম্যাপ ওয়ার্কিং-সেট নী-এর সাথে ম্যাচ করার জন্য ডিসপ্লে পিক্সেল কাউন্টের (additionalBytesPerDisplayPixel="25") সাথে সমানুপাতিকভাবে স্কেল করে।
com.android.networkstack UID (<application>) ৬৫ এমবি ৭০ এমবি ৮৫ এমবি প্রধানত বেনামী মেমরি, ক্যাপটিভ-পোর্টাল TLS, DNS এবং DHCP বার্স্ট কভার করার জন্য P95 লাইফটাইম memory.peak-এ সাইজ করা হয়েছে।
com.android.appsearch.apk UID (<application>) ১৩০ এমবি ~১০০ এমবি লক করা, আনইভিক্টেবল মেমরি এবং ~৫ এমবি হট হোস্ট ওয়ার্কিং সেট কভার করে, যেখানে লক করা অঞ্চলের জন্য হেডরুম বাড়তে পারে। কোল্ড পৃষ্ঠা ক্যাশে (P99-এ সর্বাধিক ~৩৩০ এমবি) রিক্লেম করার সময় ≥১২৫ এমবিতে পরিমাপ করা জিরো রিফল্ট।
com.android.phone (TeleService) PID (<process>) ১২০ এমবি শেয়ার করা UID 1001-এ PID প্রতি স্কোপ করা হয়েছে। ওয়ার্কিং সেট RAM-এর পরিবর্তে ডিভাইস জেনারেশন ট্র্যাক করে, তাই একটি বাজেট প্রতি-মডেল P99 anon + swap-এর সর্বোচ্চ ভ্যালুর থেকে ~৩০ এমবি বেশি হয়।

OEM কীভাবে তাদের নিজস্ব ডিভাইসের জন্য সিস্টেম অ্যাপ বাজেট রিক্যালিব্রেট করতে পারে

যেসব OEM সিস্টেম অ্যাপ কাস্টমাইজ করে (যেমন, ভেন্ডর ব্লুটুথ প্রোফাইল, কাস্টম টেলিফোনি এক্সটেনশন বা OEM মিডিয়া ইন্ডেক্সার যোগ করা) অথবা অতিরিক্ত প্রি-ইনস্টল করা সিস্টেম পরিষেবা শিপ করে, তারা আগে থেকে থাকা বাজেট রিক্যালিব্রেট করতে পারে অথবা তাদের হার্ডওয়্যার পোর্টফোলিওর জন্য নতুন *-budget.xml ফাইল তৈরি করতে পারে।

অ্যাক্টিভ cgroup v2 মেমরি প্রোফাইল সংগ্রহ করুন

প্রতিটি টার্গেট সিস্টেম প্রসেসের জন্য, /sys/fs/cgroup/uid_<uid>/pid_<pid>/-এর অধীনে এর cgroup v2 মেমরি নোড পড়ুন, যা রিপ্রেজেন্টেটিভ ওয়ার্কলোড এবং RAM টিয়ার জুড়ে রয়েছে:

  • memory.current: cgroup-এ চার্জ করা বর্তমান রেসিডেন্ট মেমরি (Zygote-শেয়ার করা পৃষ্ঠা বাদ দিয়ে)
  • memory.peak: প্রসেস শুরু হওয়ার পর থেকে লাইফটাইম পিক memory.current হাই-ওয়াটার মার্ক
  • memory.swap.current: ZRAM-এ বর্তমানে কম্প্রেস করা সোয়াপ ব্যবহার
  • memory.stat: anon, file, pgscan, pgsteal, workingset_refault_anon এবং workingset_refault_file-এর ব্রেকডাউন
  • memory.events: high লঙ্ঘনের সামগ্রিক সংখ্যা (memory.high থ্রটলিং ও রিক্লেম ইভেন্ট)

ডগফুড বা ফিল্ড ডিভাইস থেকে টেলিমেট্রি অ্যাগ্রিগেট করার সময়, অ্যাক্টিভ প্রসেস স্টেট (TOP, FOREGROUND_SERVICE, অ্যাক্টিভ বাইন্ডিং ও অ্যাক্টিভ সিঙ্ক) আইডল CACHED বা আইডল PERSISTENT স্টেট থেকে আলাদা করুন যাতে আইডল স্ন্যাপশট আপনার P95 ও P99 ওয়ার্কিং-সেট ক্যালকুলেশনকে নিচের দিকে না নামিয়ে দেয়।

রিক্লেম করা যায় এমন ফাইল ক্যাশে থেকে ইনকমপ্রেসিবল হিপ আলাদা করুন

anon + swap-এর ৯৯তম পার্সেন্টাইলের সাথে memory.current-এর ৯৯তম পার্সেন্টাইলের তুলনা করুন:

  • ফাইল-ক্যাশে-ডমিনেটেড পরিষেবা (file &gg; anon, যেমন ডেটাবেস প্রদানকারী, সার্চ ইন্ডেক্সার এবং লগ ডেমন): P99 anon + swap-এর উপরে আরামদায়ক হেডরুম (সাধারণত ১.৫x থেকে ৪x) এবং হট ফাইল পেজের জন্য একটি ওয়ার্কিং উইন্ডো প্রদান করতে android:maxMb সেট করুন। এই কনফিগারেশন কার্নেলকে অ্যানোনিমাস হিপ স্পর্শ না করেই কোল্ড আনম্যাপ করা ফাইল পৃষ্ঠাগুলি ক্রমাগত বের করে দিতে দেয়। unevictable বা file_mapped বড় হলে (যেমন লক করা মেমরি বা মেমরি-ম্যাপ করা ডেটাবেস), সেই ফুটপ্রিন্টকেও ওয়ার্কিং সেট হিসেবে গণনা করুন।
  • অ্যানোনিমাস-হিপ-ডমিনেটেড বা বার্স্টি পরিষেবা (anon, memory.current-এর বেশিরভাগ অংশ তৈরি করে, যেমন নেটওয়ার্কিং বা কানেক্টিভিটি স্ট্যাক): সাইজ android:maxMb, memory.peak-এর P90 থেকে P95 কভার করার জন্য, যাতে ট্রানজিয়েন্ট বার্স্ট লেটেন্সি-সেনসিটিভ থ্রেডে সিঙ্ক্রোনাস ZRAM সোয়াপ-আউট ট্রিগার না করে।
  • ডিসপ্লে-ইনটেনসিভ UI প্রসেস (যেমন পিকার, গ্যালারি বা সিস্টেম UI হেল্পার): আপনার সর্বনিম্ন এবং সর্বোচ্চ-রেজোলিউশন ডিসপ্লে জুড়ে বেসলাইন নন-UI ফুটপ্রিন্ট এবং প্রতি মেগাপিক্সেল ইনক্রিমেন্টাল বিটম্যাপ ফুটপ্রিন্ট পরিমাপ করুন এবং android:maxMb প্লাস android:additionalBytesPerDisplayPixel ব্যবহার করে বাজেট প্রকাশ করুন।

ফিজিক্যাল ডিভাইসে memory.high সুইপ করুন

বিল্ডে নতুন বাজেট কমিট করার আগে, আপনার অটোমেটেড CUJ টেস্ট চালানোর সময় ক্যান্ডিডেট লিমিট টেস্ট করতে am memory-limiter manual (অথবা userdebug বিল্ডে প্রসেসের memory.high cgroup নোডে সরাসরি লিখুন) ব্যবহার করুন:

# Override memory.high for a specific PID to 60 MB during a CUJ test
adb shell am memory-limiter manual <PID> 60MB

CUJ-এর আগে ও পরে memory.stat এবং memory.events মনিটর করুন:

  • বাজেট খুব কম: workingset_refault_anon বা workingset_refault_file CUJ চলাকালীন তীব্রভাবে স্পাইক করে, memory.swap.current অ্যাক্টিভ ফোরগ্রাউন্ড কাজ চলাকালীন ক্রমাগত বৃদ্ধি পায়, অথবা CUJ ফ্রেম বা বাইন্ডার লেটেন্সি রিগ্রেস করে। বাজেট বাড়িয়ে ডিফল্ট সীমার উপরে নিয়ে যান।
  • বাজেট অনেক বেশি: memory.events:high-এর পরিমাণ 0-ই থেকে যায়, এমনকি ভারী ফাইল-স্ট্রিমিং বা ইন্ডেক্সিং ওয়ার্কলোড এবং memory.stat-এ file-এর পরিমাণ কোল্ড পেজের সাথে অসীমভাবে বৃদ্ধি পাওয়ার পরেও। অ্যাক্টিভ ওয়ার্কিং সেটের জন্য বাজেট কমান।
  • বাজেট ভালভাবে ক্যালিব্রেট করা হয়েছে: সাধারণ অপারেশন চলাকালীন স্টেডি-স্টেট memory.current, memory.high-এর নিচে থাকে। ভারী ফাইল বা ক্যাশে বার্স্টের সময়, pgsteal কোল্ড ফাইল পেজ রিক্লেম করে, যেখানে workingset_refault_anon শূন্যের কাছাকাছি থাকে এবং CUJ লেটেন্সি অপরিবর্তিত থাকে।