Android 17 ขึ้นไปมีตัวจำกัดหน่วยความจำ ซึ่งเป็นบริการของระบบที่ตรวจสอบและจำกัดการใช้งานหน่วยความจำของกระบวนการแอปพลิเคชันโดยใช้ Linux cgroup v2 ตัวจำกัดหน่วยความจำจะป้องกันไม่ให้แอปแต่ละแอปใช้หน่วยความจำของระบบมากเกินไป ซึ่งจะช่วยลดแรงกดดันด้านหน่วยความจำโดยรวม และป้องกันการหยุดทำงานเนื่องจากหน่วยความจำไม่เพียงพอ (LMK) อย่างรุนแรงของกระบวนการที่สำคัญในเบื้องหน้าและกระบวนการที่แคชไว้
กลไก
ตัวจำกัดหน่วยความจำจะผสานรวมกับบริการจัดการกิจกรรม (AMS) เพื่อติดตามเหตุการณ์ในวงจรของกระบวนการและการเปลี่ยนแปลงสถานะ ตัวจำกัดหน่วยความจำจะบังคับใช้ขีดจำกัดหน่วยความจำโดยใช้ลำดับชั้น cgroup v2 ของเคอร์เนล Linux
เคอร์เนลของอุปกรณ์ต้องเปิดใช้ cgroup v2 และตัวควบคุม memory เพื่อรองรับตัวจำกัดหน่วยความจำ บริการนี้อาศัยแอตทริบิวต์ต่อไปนี้โดยเฉพาะ
memory.high- เกณฑ์การเรียกคืนแบบซอฟต์ที่ใช้กับ cgroup ของ UID แพ็กเกจ หรือ cgroup ของ PID กระบวนการเมื่อมีการใช้งานงบประมาณหน่วยความจำต่อกระบวนการ ค่าเริ่มต้นคือ 90% ของขีดจำกัดหน่วยความจำของแพลตฟอร์ม เว้นแต่จะถูกจำกัดด้วยงบประมาณหน่วยความจำ เมื่อเกินขีดจำกัด เคอร์เนลจะจำกัดการจัดสรรและเรียกคืนหน้าเว็บจาก cgroup นั้น
memory.max- เพดานหน่วยความจำแบบฮาร์ดที่ใช้กับ cgroup ของ UID แพ็กเกจที่ 100% ของขีดจำกัดหน่วยความจำของแพลตฟอร์ม หากการเรียกคืนไม่สามารถรักษาการใช้งานหน่วยความจำให้อยู่ภายใต้
memory.maxเคอร์เนลจะสิ้นสุดกระบวนการหน่วยความจำไม่เพียงพอ memory.swap.max- จำกัดพื้นที่ Swap สูงสุด เช่น ZRAM ที่ cgroup ของ PID แต่ละกระบวนการสามารถใช้ได้
ข้อกำหนด Cgroup และเคอร์เนล
อุปกรณ์ที่ใช้ Android 17 (ระดับ API 37) ขึ้นไปต้องเป็นไปตามข้อกำหนด cgroup v2 และเคอร์เนลต่อไปนี้สำหรับขีดจำกัดของแพลตฟอร์ม รวมถึงงบประมาณไฟล์ Manifest และ MemoryBudgetManager ในระดับ API 37.2 ขึ้นไป
การเปิดใช้งาน cgroup ต่อกระบวนการ: เก็บ
"NeedsActivation": trueไว้ในตัวควบคุม cgroup v2memoryใน/system/etc/cgroups.jsonเพื่อให้initเปิดใช้งาน+memoryก่อนสร้าง/sys/fs/cgroup/apps/uid_<UID>/pid_<PID>และ/sys/fs/cgroup/system/uid_<UID>/pid_<PID>อย่าปิดใช้"NeedsActivation", ตั้งค่าro.config.per_app_memcg=falseหรือเพิ่มการลบล้างของผู้ให้บริการcgroups.jsonที่ปิดใช้ cgroup ของหน่วยความจำต่อ UID หรือต่อกระบวนการ หาก/vendor/etc/task_profiles.jsonลบล้างแอตทริบิวต์ตัวควบคุมหน่วยความจำ เช่นMemLimitหรือMemSoftLimitให้เก็บ"File"ไว้โดยไม่เว้นว่าง และรวมการแมป"FileV2"กับชื่อไฟล์ cgroup v2สิทธิ์ในไฟล์ Cgroup: ไฟล์ควบคุม
uid_<UID>ระดับบนและpid_<PID>ต่อกระบวนการmemory.high,memory.maxและmemory.swap.maxภายใต้/sys/fs/cgroup/appsและ/sys/fs/cgroup/systemต้องเขียนได้โดยsystem_serverภายใต้ UID หรือ GID 1000 เพื่อให้ขีดจำกัด UID, งบประมาณกระบวนการ และขีดจำกัดการสลับมีผลโดยไม่มีข้อผิดพลาดEACCESไฟล์memory.current,memory.events,memory.events.local,memory.statและmemory.highต่อ UID และต่อกระบวนการ รวมถึงmemory.maxและmemory.swap.maxต่อ UID ต้องอ่านได้โดย UID ของแอปที่เป็นเจ้าของ เพื่อให้การค้นหาMemoryBudgetManagerและ Listener ที่เกินงบประมาณทำงานในกระบวนการการแยก PSI ในเครื่อง: แยกการหยุดชะงักของการเรียกคืน
memory.highต่อ cgroup ออกจากข้อมูลการหยุดชะงักของแรงกดดันหน่วยความจำ (PSI) ทั่วโลกโดยรวมการเปลี่ยนแปลง PSI ของ memcg ในเครื่อง GKI และเก็บrecord_psi=falseไว้ในฮุกของผู้ให้บริการandroid_vh_mem_cgroup_handle_over_highหากไม่มีการแยก PSI การจำกัดปริมาณการใช้งานmemory.highที่แปลเป็นภาษาท้องถิ่นจะเพิ่ม PSI ของหน่วยความจำส่วนกลาง และอาจทำให้เกิดการสิ้นสุดกระบวนการlmkdโดยไม่จำเป็นเมื่อหน่วยความจำทั่วทั้งระบบไม่ได้อยู่ภายใต้แรงกดดัน
ผลกระทบต่อแอป
แอปที่ทำงานภายในขีดจำกัดหน่วยความจำจะไม่ได้รับผลกระทบจากตัวจำกัดหน่วยความจำ
เมื่อแอปใช้หน่วยความจำเกินขีดจำกัด memory.high เคอร์เนลจะล้างหน่วยความจำที่สำรองไว้สำหรับไฟล์ที่ไม่มีการแก้ไขของแอป และสลับหน่วยความจำที่ไม่ระบุตัวตนที่ไม่ได้ใช้งานออกเพื่อรักษาการใช้หน่วยความจำของแอปให้อยู่ภายในขีดจำกัด ผลจากการขับหน้าและการสลับกิจกรรมนี้ แอปอาจพบการควบคุมการดำเนินการชั่วคราว แต่แอปจะยังคงทำงานต่อไป
ในสถานการณ์ที่รุนแรง เช่น หน่วยความจำรั่วไหลอย่างควบคุมไม่ได้ซึ่งแอปยังคงจัดสรรหน่วยความจำเกิน memory.max หรือหลังจากพื้นที่ Swap หมด แอปจะจัดสรรหน่วยความจำไม่สำเร็จและถูกสิ้นสุดการทำงาน
การตรวจสอบกระบวนการ
ตัวจำกัดหน่วยความจำจะใช้ขีดจำกัดของแพลตฟอร์มในหน้านี้กับกระบวนการของแอป (UID >= 10000) กระบวนการที่มี UID ต่ำกว่า 10000 จะไม่ได้รับขีดจำกัดของแพลตฟอร์ม และแพ็กเกจของบริการอนุมานที่ทำแซนด์บ็อกซ์ในอุปกรณ์เริ่มต้น (config_defaultOnDeviceSandboxedInferenceService) ก็ไม่ได้รับเช่นกัน แอปและบริการของระบบยังคงประกาศงบประมาณหน่วยความจำที่เข้มงวดขึ้นได้ตามที่อธิบายไว้ในงบประมาณหน่วยความจำของระบบ
ตัวจำกัดหน่วยความจำจะกำหนดขีดจำกัดหน่วยความจำตามสถานะการมองเห็นของกระบวนการ ดังนี้
กระบวนการที่มองเห็นได้: กระบวนการที่โฮสต์ UI ที่ผู้ใช้มองเห็นได้ เช่น กิจกรรมที่โฟกัสหรือการโต้ตอบที่ใช้งานอยู่ เนื่องจากการแสดง UI ต้องใช้ชุดการทำงานที่ใหญ่ขึ้นสำหรับไปป์ไลน์การแสดงผลและกราฟิก กระบวนการที่มองเห็นได้จึงได้รับขีดจำกัดหน่วยความจำที่มากขึ้น
กระบวนการที่มองไม่เห็น: กระบวนการที่ทำงานอยู่เบื้องหลังโดยไม่แสดง UI เช่น บริการที่ทำงานอยู่เบื้องหลังหรือ Broadcast Receiver เนื่องจากไม่ได้แสดงผลคอมโพเนนต์ UI จึงทำงานภายใต้ขีดจำกัดที่เข้มงวดกว่า
ตารางต่อไปนี้จะจับคู่สถานะกระบวนการที่เฉพาะเจาะจงกับการจัดประเภทขีดจำกัดหน่วยความจำของแพลตฟอร์ม
| สถานะกระบวนการ | ขีดจำกัดหน่วยความจำ |
|---|---|
PERSISTENT |
ไม่จำกัด |
PERSISTENT_UI |
ไม่จำกัด |
TOP |
visible |
BOUND_TOP |
visible |
FOREGROUND_SERVICE |
not-visible |
BOUND_FOREGROUND_SERVICE |
not-visible |
IMPORTANT_FOREGROUND |
visible |
IMPORTANT_BACKGROUND |
not-visible |
TRANSIENT_BACKGROUND |
not-visible |
BACKUP |
not-visible |
SERVICE |
not-visible |
RECEIVER |
not-visible |
TOP_SLEEPING |
visible |
HEAVY_WEIGHT |
not-visible |
HOME |
not-visible |
LAST_ACTIVITY |
not-visible |
CACHED_ACTIVITY |
not-visible |
CACHED_ACTIVITY_CLIENT |
not-visible |
CACHED_RECENT |
not-visible |
CACHED_EMPTY |
not-visible |
กระบวนการ PERSISTENT และ PERSISTENT_UI ไม่ได้รับขีดจำกัดของแพลตฟอร์ม หากกระบวนการใดกระบวนการหนึ่งเหล่านี้ประกาศงบประมาณหน่วยความจำ ระบบจะใช้งบประมาณเบื้องหน้าตามที่อธิบายไว้ในที่เก็บงบประมาณหน่วยความจำ
ในสถานะแคช กระบวนการต่างๆ จะยังคงมีขีดจำกัดแพลตฟอร์ม not-visible ควบคู่ไปกับการหยุดทำงานและการบีบอัดแอปที่แคชไว้ ซึ่งจะทำให้กระบวนการต่างๆ ถูกจำกัดไว้แม้ว่าจะไม่มีการหยุดทำงานหรือการเรียกคืนทรัพยากรสูงสุดก็ตาม
เมื่อกระบวนการใช้หน่วยความจำเกินขีดจำกัด memory.high ที่กำหนดไว้ ตัวจำกัดหน่วยความจำจะตรวจพบเหตุการณ์และสามารถเรียกใช้การดำเนินการวินิจฉัย เช่น บันทึกโปรไฟล์หน่วยความจำหรือบันทึกความผิดปกติลงใน statsd
ที่เก็บข้อมูลงบประมาณหน่วยความจำ
ในระดับ API 37.2 ขึ้นไป แอปและบริการของระบบสามารถประกาศงบประมาณหน่วยความจำที่เข้มงวดกว่าขีดจำกัดของแพลตฟอร์ม หรือตั้งค่างบประมาณรันไทม์ที่เข้มงวดขึ้นผ่าน MemoryBudgetManager แอปจะกำหนดค่างบประมาณตามที่อธิบายไว้ในกำหนดงบประมาณหน่วยความจำของแอป สำหรับแอปและบริการของระบบ โปรดดูงบประมาณหน่วยความจำของระบบ งบประมาณจะกำหนด memory.high และต้องไม่เกินขีดจำกัดของแพลตฟอร์มสำหรับสถานะกระบวนการเดียวกัน และงบประมาณรันไทม์ต้องไม่เกินงบประมาณไฟล์ Manifest ที่เกี่ยวข้อง
เมื่อกระบวนการประกาศงบประมาณที่ระบุไว้ ตัวจำกัดหน่วยความจำจะแมปสถานะกระบวนการกับที่เก็บงบประมาณ 1 ใน 3 แห่ง ส่วนงบประมาณรันไทม์จะใช้เพดานเดียวจนกว่าจะอัปเดตหรือล้าง ค่า android:state ของไฟล์ Manifest
foreground, perceptible และ background จะระบุงบประมาณสำหรับที่เก็บข้อมูลที่ตรงกัน กระบวนการที่แคชไว้ในสถานะ CACHED_ACTIVITY ถึง CACHED_EMPTY จะคงงบประมาณ background ไว้ควบคู่ไปกับการหยุดทำงานชั่วคราวและการบีบอัดแอปที่แคชไว้
| สถานะกระบวนการ | กลุ่มงบประมาณ |
|---|---|
PERSISTENT | ฉากหน้า |
PERSISTENT_UI | ฉากหน้า |
TOP | ฉากหน้า |
BOUND_TOP | ฉากหน้า |
TOP_SLEEPING | ฉากหน้า |
FOREGROUND_SERVICE | รับรู้ได้ |
BOUND_FOREGROUND_SERVICE | รับรู้ได้ |
IMPORTANT_FOREGROUND | รับรู้ได้ |
IMPORTANT_BACKGROUND | รับรู้ได้ |
TRANSIENT_BACKGROUND | ฉากหลัง |
BACKUP | ฉากหลัง |
SERVICE | ฉากหลัง |
RECEIVER | ฉากหลัง |
HEAVY_WEIGHT | ฉากหลัง |
HOME | ฉากหลัง |
LAST_ACTIVITY | ฉากหลัง |
CACHED_ACTIVITY | ฉากหลัง |
CACHED_ACTIVITY_CLIENT | ฉากหลัง |
CACHED_RECENT | ฉากหลัง |
CACHED_EMPTY | ฉากหลัง |
การกำหนดค่า
ใน 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 minimumRequiredMemTotalMemTotalขั้นต่ำของระบบ (เป็น MiB, รวมค่าต่ำสุด) ที่จำเป็นสำหรับการใช้ชุดขีดจำกัดนี้ บริการจะประเมินค่านี้เทียบกับหน่วยความจำทั้งหมดที่ใช้ได้ซึ่งรายงานโดยเคอร์เนลใน/proc/meminfoทำความเข้าใจการแบ่งส่วนและขอบเขตของหน่วยความจำ: ค่า
MemTotalของเคอร์เนลจะแสดง DRAM ทางกายภาพที่ระบบปฏิบัติการเข้าถึงได้หลังจากหักการแบ่งส่วนหน่วยความจำของฮาร์ดแวร์และเฟิร์มแวร์ออกแล้ว Carve-out จะสำรอง RAM ไว้สำหรับคอมโพเนนต์ฮาร์ดแวร์เฉพาะทาง เช่น GPU, โมเด็มเบสแบนด์, ISP ของกล้อง, สภาพแวดล้อมการดำเนินการที่ปลอดภัย และไฮเปอร์ไวเซอร์ ซึ่งโดยปกติจะใช้หน่วยความจำกายภาพระหว่าง 500 MiB ถึงมากกว่า 2 GiBเนื่องจาก
MemTotalต่ำกว่า DRAM จริงที่โฆษณาไว้ของอุปกรณ์ เกณฑ์minimumRequiredMemTotalจึงรวมส่วนต่างสำหรับการกันทรัพยากรเหล่านี้ไว้ด้วย ตัวอย่างเช่น การกำหนดค่าที่กำหนดเป้าหมายอุปกรณ์ขนาด 16 GB จะระบุขีดจำกัดต่ำสุดเป็น14336(14 GiB) แทนที่จะเป็น16384(16 GiB) และระดับสำหรับอุปกรณ์ขนาด 12 GB จะระบุขีดจำกัดต่ำสุดเป็น9216(9 GiB) วิธีนี้ช่วยให้มั่นใจได้ว่าอุปกรณ์แต่ละเครื่องจะตรงกับระดับที่ต้องการ ไม่ว่าจะมีรูปแบบการแยกส่วนระดับบอร์ดที่แตกต่างกันอย่างไรก็ตามmaximumAllowedMemTotalMemTotalสูงสุดของระบบ (เป็น MiB, เพดานแบบไม่รวม) สำหรับชุดขีดจำกัดนี้ที่จะใช้ หากMemTotalมากกว่าหรือเท่ากับเพดานนี้ ขีดจำกัดที่ตั้งไว้จะไม่มีผล สำหรับอุปกรณ์ที่มีMemTotalน้อยกว่า 3,200 MiB หรืออย่างน้อย 18,432 MiB ตัวจำกัดหน่วยความจำจะไม่ใช้ขีดจำกัดแพลตฟอร์มเริ่มต้น แม้ว่า cgroup ของหน่วยความจำต่อกระบวนการจะยังคงทำงานอยู่ (พร้อมกับงบประมาณรันไทม์ของไฟล์ Manifest, ระบบ และMemoryBudgetManagerในระดับ API 37.2 ขึ้นไป)memVisibleขีดจำกัดหน่วยความจำแบบฮาร์ด
memory.maxในหน่วย MiB ที่ใช้กับ UID ของแพ็กเกจ cgroup เมื่อแพ็กเกจมีกระบวนการที่มองเห็นได้ เกณฑ์การเรียกคืนแบบซอฟต์memory.highเริ่มต้นคือ 90% ของค่านี้ โดยปัดเศษเป็น MiB ที่ใกล้เคียงที่สุดmemNotVisibleขีดจำกัดหน่วยความจำแบบฮาร์ด
memory.maxในหน่วย MiB ที่ใช้กับ UID ของแพ็กเกจ cgroup เมื่อแพ็กเกจไม่มีกระบวนการที่มองเห็นได้ เกณฑ์การเรียกคืนแบบซอฟต์ของmemory.highเริ่มต้นคือ 90% ของค่านี้ โดยปัดเศษเป็น MiB ที่ใกล้เคียงที่สุดswapVisibleขีดจำกัดพื้นที่ Swap
memory.swap.maxในหน่วย MiB ที่ใช้กับ cgroup ของ PID ของกระบวนการที่มองเห็นได้แต่ละรายการswapNotVisibleขีดจำกัดพื้นที่ Swap
memory.swap.maxในหน่วย MiB ที่ใช้กับ cgroup ของ PID ของกระบวนการที่ไม่แสดงแต่ละรายการ
ขีดจำกัดมาตรฐานของแพลตฟอร์ม
ใน Android 17 ขึ้นไป แพลตฟอร์มจะระบุขีดจำกัดหน่วยความจำมาตรฐานและสวอปเป็น /system/etc/memory-limiter-config.xml ในระดับ RAM จริงทั่วไปโดยใช้ช่วง [floor, ceiling) ดังนี้
| RAM จริงเป้าหมาย |
ช่วง MemTotal [ต่ำสุด, สูงสุด) (minimumRequiredMemTotal, maximumAllowedMemTotal) |
ขีดจำกัดหน่วยความจำที่มองเห็นได้ (memVisible) |
ขีดจำกัดหน่วยความจำที่มองไม่เห็น (memNotVisible) |
ขีดจำกัดการสลับที่มองเห็นได้ (swapVisible) |
ขีดจำกัดการสลับที่ไม่แสดง (swapNotVisible) |
|---|---|---|---|---|---|
| 16 GB | [14336, 18432) MiB |
10,240 MiB (10 GiB) | 5,120 MiB (5 GiB) | 5,120 MiB (5 GiB) | 5,120 MiB (5 GiB) |
| 12 GB | [9216, 14336) MiB |
8,192 MiB (8 GiB) | 4,096 MiB (4 GiB) | 4,096 MiB (4 GiB) | 4,096 MiB (4 GiB) |
| 8 GB | [6800, 9216) MiB |
5,120 MiB (5 GiB) | 3,072 MiB (3 GiB) | 3,072 MiB (3 GiB) | 3,072 MiB (3 GiB) |
| 6 GB | [4800, 6800) MiB |
4,096 MiB (4 GiB) | 2,048 MiB (2 GiB) | 2,048 MiB (2 GiB) | 2,048 MiB (2 GiB) |
| 4 GB | [3200, 4800) MiB |
2,048 MiB (2 GiB) | 1,024 MiB (1 GiB) | 1,024 MiB (1 GiB) | 1,024 MiB (1 GiB) |
หลักการจำกัดหน่วยความจำ
การกำหนดค่าตัวจำกัดหน่วยความจำได้รับการออกแบบตามหลักการของแพลตฟอร์มต่อไปนี้
ความสอดคล้องกันของระบบนิเวศและความเข้ากันได้ของแอป: ขีดจำกัดหน่วยความจำที่สอดคล้องกันในอุปกรณ์ต่างๆ ช่วยให้มั่นใจได้ว่าประสิทธิภาพของแอปจะคาดการณ์ได้ทั่วทั้งระบบนิเวศของ Android แอปได้รับการพัฒนาและทดสอบตามความคาดหวังด้านหน่วยความจำมาตรฐาน การรักษาขีดจำกัดของแพลตฟอร์มให้สม่ำเสมอจะช่วยหลีกเลี่ยงการควบคุมปริมาณที่ไม่คาดคิดหรือการสิ้นสุดก่อนเวลาอันควร
การจัดสรรทรัพยากรตามสัดส่วน: ขีดจำกัดของแพลตฟอร์มจะได้รับการปรับเทียบตามความจุ RAM จริง ดังนี้
- กระบวนการที่มองเห็นได้: จัดสรร RAM จริงทั้งหมดประมาณ 1/2 ถึง 2/3 เพื่อรองรับภาระงาน UI, องค์ประกอบ และการแสดงผลที่ใช้งานอยู่
- กระบวนการที่ไม่แสดง: จัดสรร RAM จริงประมาณ 1/4 ถึง 1/3 ของทั้งหมดสำหรับงานที่ทำงานอยู่เบื้องหลัง
การบังคับใช้แบบครอบคลุม: ขีดจำกัดจะมีผลกับกระบวนการทั้งหมดของแอปพลิเคชันในอุปกรณ์อย่างเท่าเทียมกัน (UID >= 10000) ซึ่งรวมถึงระบบที่ติดตั้งล่วงหน้าและแอป OEM นอกเหนือจากบริการอนุมานที่ทำแซนด์บ็อกซ์ในอุปกรณ์โดยค่าเริ่มต้นแล้ว ตัวจำกัดหน่วยความจำจะไม่ยกเว้นแอปแต่ละแอป เพื่อให้มั่นใจว่ามีการกำกับดูแลหน่วยความจำอย่างเป็นธรรมในแอปทั้งหมด หากต้องการกำหนดค่าขีดจำกัดขั้นต่ำของการป้องกัน
memory.minที่ปรับแต่งเองใน Daemon แบบอินเทอร์แอกทีฟที่สำคัญ และขีดจำกัดสูงสุดของmemory.highที่ปรับเทียบภาระงานให้เข้มงวดยิ่งขึ้นในแอปและบริการของระบบแต่ละรายการ โปรดดูงบประมาณหน่วยความจำของระบบงบประมาณรันไทม์ที่คาดการณ์ได้: ในระดับ API 37.2 ขึ้นไป แอปสามารถค้นหาขีดจำกัดหน่วยความจำและการใช้งานหน่วยความจำ cgroup และตั้งค่างบประมาณรันไทม์ที่เข้มงวดขึ้นผ่าน
MemoryBudgetManagerการคงขีดจำกัดของแพลตฟอร์มและไฟล์ Manifest มาตรฐานไว้โดยไม่มีการลบล้างของผู้ให้บริการจะช่วยให้ลักษณะการทำงานของงบประมาณรันไทม์สอดคล้องกันในอุปกรณ์ต่างๆการเรียกคืนเคอร์เนลและไดนามิกการสลับ: เมื่อกระบวนการของแอปใกล้ถึงขีดจำกัด
memory.highเคอร์เนล Linux จะกำหนดให้มีการเรียกคืนหน่วยความจำโดยเฉพาะที่ cgroup ของกระบวนการนั้น ซึ่งรวมถึงการทิ้งหน้าเว็บที่สำรองข้อมูลไฟล์ที่ไม่ได้ใช้งานและการสลับหน้าเว็บที่ไม่ระบุตัวตนที่ไม่ได้ใช้งานไปยัง ZRAM เพื่อรักษาความลื่นไหลของระบบโดยไม่สร้างแรงกดดันต่อหน่วยความจำส่วนกลาง
คำสั่ง Shell
คำสั่ง am memory-limiter ช่วยให้นักพัฒนาซอฟต์แวร์และผู้ผสานรวมระบบโต้ตอบกับบริการขณะรันไทม์เพื่อการพัฒนา การทดสอบ และการแก้ไขข้อบกพร่องได้ ดังนี้
am memory-limiter <SUB-COMMAND>สถานะ
คำสั่งย่อย status จะรายงานสถานะการดำเนินการ ขีดจำกัดของแพลตฟอร์มที่กำหนดค่าไว้ และตัวนับการตรวจสอบที่ใช้งานอยู่ของตัวจำกัดหน่วยความจำ ดังนี้
adb shell am memory-limiter statusการเรียกใช้ adb shell am memory-limiter status version จะพิมพ์ 2 เมื่อเปิดใช้ตัวจำกัดหน่วยความจำ 2 เกณฑ์ หรือ 0 เมื่อปิดใช้
ต่อไปนี้คือตัวอย่างเอาต์พุต status ในอุปกรณ์ขนาด 8 GB
Memory limiter
enabled limits=true killing=true ignored=none
visible: memHigh=4608MB memMax=5120MB swapMax=3072MB
not-visible: memHigh=2765MB memMax=3072MB swapMax=3072MB
active=64 uid-started=32 uid-current=28 uid-updated=4
started=72 watched=72 watch-failed=0
limiters=64 limiters-hwm=70 red-poll=0 red-limiter=0
events=0 false-events=0 modify=84
ช่องหลักในเอาต์พุตมีดังนี้
limitsและkilling- ระบุว่ามีการกำหนดค่าและบังคับใช้ขีดจำกัดหน่วยความจำของแพลตฟอร์ม
memory.highและmemory.maxสำหรับระดับ RAM ของอุปกรณ์หรือไม่ ignored- UID ที่ยกเว้นโดยคำสั่งย่อย
ignore,allเมื่อการจำกัดหยุดชั่วคราวทั่วโลก หรือnone visibleและnot-visible- ขีดจำกัด UID
memHighเริ่มต้นสำหรับmemory.high, ขีดจำกัด UIDmemMaxสำหรับmemory.maxและขีดจำกัดswapMaxต่อกระบวนการสำหรับmemory.swap.maxที่บังคับใช้สำหรับการจัดประเภทระดับการเข้าถึงแต่ละรายการ active- จำนวนกระบวนการที่ติดตามและตัวจำกัด UID ใน
system_server uid-started,uid-currentและuid-updated- จำนวนสะสมที่เริ่ม จำนวนที่ใช้งานอยู่ และจำนวนสะสมที่แทนที่สำหรับตัวจำกัด UID ที่อัปเดตด้วยงบประมาณไฟล์ Manifest
watchedและwatch-failed- จำนวนสะสมของการเฝ้าติดตาม cgroup
memory.eventsที่ลงทะเบียนและไม่สำเร็จ limitersและlimiters-hwm- จำนวนและระดับสูงสุดของ Watcher ของ Cgroup แบบเนทีฟที่ใช้งานอยู่
eventsและfalse-events- จำนวนเหตุการณ์ที่เกินขีดจำกัดซึ่งส่งไปยัง
system_serverและการแจ้งเตือนmemory.eventsที่ไม่เกินเกณฑ์ที่ตรวจสอบ
ignore
คำสั่งย่อย 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 จะลบล้างขีดจำกัด memory.high, memory.max และ memory.swap.max ที่คำนวณไว้ด้วยเพดานจำนวนเต็มที่กำหนดเองจนถึงขีดจำกัดที่กำหนดค่าไว้ของเป้าหมาย ส่ง PID โดยมีหรือไม่มี -p เพื่อกำหนดเป้าหมายกระบวนการเดียว หรือส่ง -u <UID> เพื่อกำหนดเป้าหมายกระบวนการทั้งหมดใน UID ของแพ็กเกจ ระบุขนาดเป็นไบต์ ต่อท้ายด้วย MB สำหรับ MiB หรือ GB สำหรับ GiB หรือส่ง none เพื่อล้างการลบล้าง เพื่อความเข้ากันได้แบบย้อนหลัง จำนวนเต็มที่ต่ำกว่า 20 ที่ไม่มีคำต่อท้ายจะตีความว่าเป็น MiB ดังนี้
# Set a 1 GiB limit for PID 1234, with or without -p adb shell am memory-limiter manual 1234 1073741824 adb shell am memory-limiter manual 1234 1024MB adb shell am memory-limiter manual -p 1234 1GB# Set a 1 GiB limit for all processes in UID 10087 adb shell am memory-limiter manual -u 10087 1GB# Remove the manual override for PID 1234 or UID 10087 adb shell am memory-limiter manual 1234 none adb shell am memory-limiter manual -u 10087 none
การลบล้างกระบวนการด้วยตนเองจะมีผลเฉพาะตลอดอายุของอินสแตนซ์กระบวนการนั้นๆ เท่านั้น หากกระบวนการเริ่มต้นใหม่ ระบบจะกลับไปใช้ขีดจำกัดมาตรฐานตามสถานะของกระบวนการ ในทางตรงกันข้าม การลบล้าง manual -u <UID> จะยังคงอยู่ขณะที่ UID ยังคงทำงานอยู่ จนกว่ากระบวนการทั้งหมดใน UID จะออกหรือคุณล้างการลบล้างด้วย none
การลบล้างด้วยตนเองต้องไม่เกินขีดจำกัดของระบบทางกายภาพ