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

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

กลไก

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

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

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

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

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

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

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

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

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

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

  • กระบวนการที่แสดง อยู่ในสถานะที่แสดง UI ต่อผู้ใช้ได้ ขณะแสดง UI กระบวนการอาจใช้ชุดการทำงานของ RAM มากขึ้น ดังนั้นจึงได้รับขีดจำกัดหน่วยความจำที่สูงขึ้น

  • กระบวนการที่ไม่แสดง อยู่ในสถานะที่ทำงานอยู่แต่ไม่ได้แสดง 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

การกำหนดค่า

กำหนดค่าตัวจำกัดหน่วยความจำโดยใช้ไฟล์ 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) ที่อนุญาตสำหรับกระบวนการที่ไม่แสดง

หลักเกณฑ์ขีดจำกัดหน่วยความจำของอุปกรณ์

เมื่อกำหนดค่าขีดจำกัดหน่วยความจำสำหรับอุปกรณ์ ให้พิจารณาหลักเกณฑ์ต่อไปนี้

  • ปรับขีดจำกัดให้เหมาะกับความสามารถของฮาร์ดแวร์: ผู้ผลิตอุปกรณ์ (OEM) สามารถกำหนดขีดจำกัดที่ปรับให้เหมาะกับความสามารถของฮาร์ดแวร์ของอุปกรณ์ได้ Android แนะนำช่วงต่อไปนี้

    • กระบวนการที่แสดง: อย่างน้อย 1/2 และอย่างมาก 2/3 ของ RAM จริงทั้งหมด
    • กระบวนการที่ไม่แสดง: 1/4 ถึง 1/3 ของ RAM จริงทั้งหมด OEM สามารถกำหนดค่าที่แตกต่างกันได้โดยอิงตามความสามารถของอุปกรณ์และกรณีการใช้งาน
  • ไม่มี API รันไทม์สำหรับแอป: ตั้งแต่ Android 17 (SDK 37) เป็นต้นมา แอปจะไม่มี API สำหรับค้นหาขีดจำกัดหน่วยความจำในรันไทม์ OEM ควรพิจารณาเรื่องนี้และหลีกเลี่ยงการกำหนดขีดจำกัดที่ต่ำเกินไป เพื่อให้มั่นใจว่าแอปจะไม่ถึงขีดจำกัดในกรณีการใช้งานที่สมเหตุสมผล

  • การกำหนดค่าสากล: ขีดจำกัดจะมีผลกับกระบวนการของแอปทั้งหมดในอุปกรณ์ รวมถึงแอปที่ติดตั้งไว้ล่วงหน้า ไม่มีรายการที่อนุญาตให้ยกเว้นแอปบางแอปจากขีดจำกัดเหล่านี้

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

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

  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

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