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

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 v2 memory ใน /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
minimumRequiredMemTotal

MemTotal ขั้นต่ำของระบบ (เป็น 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) วิธีนี้ช่วยให้มั่นใจได้ว่าอุปกรณ์แต่ละเครื่องจะตรงกับระดับที่ต้องการ ไม่ว่าจะมีรูปแบบการแยกส่วนระดับบอร์ดที่แตกต่างกันอย่างไรก็ตาม

maximumAllowedMemTotal

MemTotalสูงสุดของระบบ (เป็น 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, ขีดจำกัด UID memMax สำหรับ 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

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