ตัวจำกัดหน่วยความจำ

Android 17 ขึ้นไปรองรับตัวจำกัดหน่วยความจำ ซึ่งเป็นบริการของระบบที่ตรวจสอบและจำกัดการใช้งานหน่วยความจำของกระบวนการแอปพลิเคชันโดยใช้ cgroup v2 ของ Linux ตัวจำกัดหน่วยความจำจะป้องกันไม่ให้แอปแต่ละแอปใช้หน่วยความจำของระบบมากเกินไป ซึ่งจะช่วยลดแรงกดดันด้านหน่วยความจำทั่วทั้งระบบและป้องกันการหยุดกระบวนการที่สำคัญอย่างรุนแรงเนื่องจากหน่วยความจำไม่เพียงพอ (OOM)

กลไก

ตัวจำกัดหน่วยความจำจะผสานรวมกับบริการ Activity Manager (AMS) เพื่อติดตามเหตุการณ์วงจรการทำงานของกระบวนการและการเปลี่ยนแปลงสถานะ ตัวจำกัดหน่วยความจำจะบังคับใช้ขีดจำกัดหน่วยความจำโดยใช้ระบบไฟล์ cgroup v2 ของเคอร์เนล Linux

หากต้องการใช้ตัวจำกัดหน่วยความจำ เคอร์เนลของอุปกรณ์ต้องรองรับ cgroup v2 และตัวควบคุม memory บริการนี้อาศัยแอตทริบิวต์ต่อไปนี้โดยเฉพาะ

memory.high
ขีดจำกัดแบบไม่เข้มงวด เมื่อเกินขีดจำกัด กระบวนการจะถูกจำกัดความเร็วและเคอร์เนลจะพยายามเรียกคืนหน่วยความจำจากกระบวนการนั้น
memory.swap.max
จำกัดปริมาณพื้นที่สวอปที่กระบวนการใช้ได้

ผลกระทบต่อแอป

แอปที่ไม่เกินขีดจำกัดหน่วยความจำจะไม่ได้รับผลกระทบจากตัวจำกัดหน่วยความจำ

เมื่อแอปเกินขีดจำกัด memory.high เคอร์เนลจะนำหน่วยความจำที่สำรองไว้ในไฟล์ของแอปออกและสวอปหน่วยความจำที่ไม่ระบุชื่อออกเพื่อให้แอปอยู่ในขีดจำกัด การนำออกและการสวอปอาจทำให้แอปทำงานช้าลง

ในกรณีที่ร้ายแรงที่สุด หากแอปยังคงจัดสรรหน่วยความจำที่ไม่ระบุชื่อและอุปกรณ์มีพื้นที่สวอปไม่เพียงพอ แอปอาจจัดสรรหน่วยความจำไม่สำเร็จและมีแนวโน้มที่จะหยุดทำงาน

การตรวจสอบกระบวนการ

ตัวจำกัดหน่วยความจำจะตรวจสอบกระบวนการของแอป (UID >= 10000) โดยค่าเริ่มต้น โดยทั่วไปแล้วกระบวนการของระบบจะได้รับการยกเว้นเพื่อช่วยยืนยันความเสถียรของระบบหลัก

ตัวจำกัดหน่วยความจำจะกำหนดขีดจำกัดหน่วยความจำตามสถานะของกระบวนการ ดังนี้

  • กระบวนการที่แสดง คือกระบวนการที่ผู้ใช้รับรู้ได้ เช่น กิจกรรมเบื้องหน้า บริการเบื้องหน้า หรือสถานะอื่นๆ ที่ผู้ใช้รับรู้ได้ว่ามีการกระตุก

  • กระบวนการที่ไม่แสดง คือกระบวนการเบื้องหลังที่ไม่ได้โต้ตอบกับผู้ใช้หรือผู้ใช้มองไม่เห็น

ตารางต่อไปนี้แสดงการจับคู่สถานะกระบวนการที่เฉพาะเจาะจงกับขีดจำกัดหน่วยความจำ

สถานะกระบวนการขีดจำกัดหน่วยความจำ
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

การกำหนดค่า

กำหนดค่าตัวจำกัดหน่วยความจำโดยใช้ไฟล์ XML ที่อยู่ในพาร์ติชัน vendor การกำหนดค่าช่วยให้คุณปรับขีดจำกัดหน่วยความจำสัมบูรณ์ตามข้อจำกัดหน่วยความจำที่เฉพาะเจาะจงของอุปกรณ์ได้

  • เส้นทางไฟล์: /vendor/etc/memory-limiter-config.xml

  • การกำหนดค่าเริ่มต้น: หากไม่พบไฟล์การกำหนดค่า หรือหากอ่านไม่ได้หรือไม่ถูกต้อง ตัวจำกัดหน่วยความจำจะถูกปิดใช้

รูปแบบ XML

ไฟล์การกำหนดค่าเป็นไปตามสคีมาที่กำหนดไว้ใน memory-limiter-config.xsd ไฟล์นี้ช่วยให้คุณกำหนดชุดขีดจำกัดได้หลายชุด โดยบริการจะเลือกชุดที่เหมาะสมที่สุดตาม RAM ที่พร้อมใช้งานของอุปกรณ์ ค่าหน่วยความจำทั้งหมดจะกำหนดเป็นหน่วยเมบิไบต์ (MiB)

<MemoryLimiterConfig>
  <version>1</version>
  <configList>
    <limitSet>
      <!-- Limits for a phone with at least 14G of ram: 8G/4G/4G/4G -->
      <minimumRequiredMemTotal>14336</minimumRequiredMemTotal>
      <memVisible>8192</memVisible>
      <memNotVisible>4096</memNotVisible>
      <swapVisible>4096</swapVisible>
      <swapNotVisible>4096</swapNotVisible>
    </limitSet>
  </configList>
</MemoryLimiterConfig>
version
จำนวนเต็มบวกที่ระบุเวอร์ชันการกำหนดค่า ซึ่งต้องเป็น 1
minimumRequiredMemTotal
หน่วยความจำของระบบที่พร้อมใช้งานขั้นต่ำที่จำเป็นเพื่อให้ชุดขีดจำกัดนี้ถูกต้อง
memVisible
ขีดจำกัดหน่วยความจำ (memory.high) ที่อนุญาตสำหรับกระบวนการที่แสดง
memNotVisible
ขีดจำกัดหน่วยความจำ (memory.high) ที่อนุญาตสำหรับกระบวนการที่ไม่แสดง
swapVisible
ขีดจำกัดการสวอป (memory.swap.max) ที่อนุญาตสำหรับกระบวนการที่แสดง
swapNotVisible
ขีดจำกัดการสวอป (memory.swap.max) ที่อนุญาตสำหรับกระบวนการที่ไม่แสดง

แก้ไขการกำหนดค่า

หากต้องการเปลี่ยนขีดจำกัดทั่วทั้งระบบ ให้ทำตามขั้นตอนต่อไปนี้

  1. แก้ไข /vendor/etc/memory-limiter-config.xml
  2. รีบูตอุปกรณ์หรือรีสตาร์ท system_server เพื่อให้การเปลี่ยนแปลงมีผล

คำสั่ง Shell

คำสั่ง 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
ระบุขีดจำกัดหน่วยความจำสัมบูรณ์ที่คำนวณได้สำหรับแต่ละสถานะ
events
จำนวนครั้งที่กระบวนการเกินขีดจำกัด
processes
จำนวนกระบวนการที่ตรวจสอบ

ไม่สนใจ

คำสั่งย่อย ignore จะยกเว้น UID หรือกระบวนการทั้งหมดชั่วคราวไม่ให้ถูกจำกัด การดำเนินการนี้มีประโยชน์สำหรับการทดสอบประสิทธิภาพหรือเมื่อต้องการอนุญาตให้แอปที่เฉพาะเจาะจงเกินขีดจำกัด

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

ด้วยตนเอง

คำสั่งย่อย manual จะลบล้างขีดจำกัดที่คำนวณได้สำหรับกระบวนการที่เฉพาะเจาะจง (ตามรหัสกระบวนการหรือ PID) ด้วยค่าสัมบูรณ์ที่กำหนดเองในหน่วยเมกะไบต์ (MB) โดยทำดังนี้

adb shell am memory-limiter manual 1234 1024   // Set a 1024 MB limit for PID 1234
adb shell am memory-limiter manual 1234 none // Remove the manual override for PID 1234

การลบล้างด้วยตนเองจะมีผลกับวงจรการทำงานของกระบวนการเท่านั้น หากกระบวนการรีสตาร์ท ระบบจะกลับไปใช้ขีดจำกัดเริ่มต้นตามสถานะของกระบวนการ