ภูตนักฆ่าหน่วยความจำต่ำ

กระบวนการ daemon นักฆ่าหน่วยความจำต่ำ ( lmkd ) ของ Android จะตรวจสอบสถานะหน่วยความจำของระบบ Android ที่ทำงานอยู่และตอบสนองต่อแรงดันหน่วยความจำสูงโดยการฆ่ากระบวนการที่จำเป็นน้อยที่สุดเพื่อให้ระบบทำงานในระดับที่ยอมรับได้

เกี่ยวกับหน่วยความจำความดัน

ระบบ Android ที่ทำงานหลายขั้นตอนพร้อมกันอาจพบกับสถานการณ์เมื่อหน่วยความจำระบบหมดและกระบวนการที่ต้องใช้หน่วยความจำมากขึ้นจะเกิดความล่าช้าอย่างเห็นได้ชัด ความดันหน่วยความจำ สถานะที่ระบบใช้หน่วยความจำไม่เพียงพอ ต้องใช้ Android เพื่อเพิ่มหน่วยความจำ (เพื่อบรรเทาแรงกดดัน) โดยการควบคุมปริมาณหรือฆ่ากระบวนการที่ไม่สำคัญ ขอให้กระบวนการเพิ่มทรัพยากรแคชที่ไม่สำคัญ และอื่นๆ

ในอดีต Android ได้ตรวจสอบความดันของหน่วยความจำระบบโดยใช้ไดรเวอร์ in-kernel low memory killer (LMK) ซึ่งเป็นกลไกที่เข้มงวดซึ่งขึ้นอยู่กับค่าฮาร์ดโค้ด ณ เคอร์เนล 4.12 ไดรเวอร์ LMK จะถูกลบออกจากเคอร์เนลอัปสตรีมและ userspace lmkd ดำเนินการตรวจสอบหน่วยความจำและดำเนินการฆ่ากระบวนการ

ข้อมูลแผงความดัน

Android 10 และใหม่กว่ารองรับโหมด lmkd ใหม่ที่ใช้ตัวตรวจสอบข้อมูลแรงดันเคอร์เนล (PSI) สำหรับการตรวจจับแรงดันหน่วยความจำ ชุดแพตช์ PSI ในเคอร์เนลอัปสตรีม (แบ็คพอร์ตเป็นเคอร์เนล 4.9 และ 4.14) จะวัดระยะเวลาที่งานล่าช้าอันเป็นผลมาจากการขาดแคลนหน่วยความจำ เนื่องจากความล่าช้าเหล่านี้ส่งผลโดยตรงต่อประสบการณ์ของผู้ใช้ จึงเป็นตัวชี้วัดที่สะดวกสำหรับการพิจารณาความรุนแรงของแรงดันหน่วยความจำ เคอร์เนลต้นน้ำยังรวมถึงการมอนิเตอร์ PSI ที่อนุญาตให้กระบวนการ userspace ที่มีสิทธิพิเศษ (เช่น lmkd ) เพื่อระบุขีดจำกัดสำหรับความล่าช้าเหล่านี้ และเพื่อสมัครรับเหตุการณ์จากเคอร์เนลเมื่อมีการละเมิดขีดจำกัด

มอนิเตอร์ PSI กับสัญญาณ vmpressure

เนื่องจากสัญญาณ vmpressure (สร้างโดยเคอร์เนลสำหรับการตรวจจับแรงดันหน่วยความจำและใช้โดย lmkd ) มักจะรวมผลบวกปลอมจำนวนมาก lmkd จึงต้องทำการกรองเพื่อตรวจสอบว่าหน่วยความจำอยู่ภายใต้แรงกดดันจริงหรือไม่ ส่งผลให้เกิดการ lmkd ที่ไม่จำเป็นและการใช้ทรัพยากรการคำนวณเพิ่มเติม การใช้มอนิเตอร์ PSI ส่งผลให้การตรวจจับแรงดันหน่วยความจำแม่นยำยิ่งขึ้น และลดค่าใช้จ่ายในการกรองให้เหลือน้อยที่สุด

การใช้จอภาพ PSI

เมื่อต้องการใช้การมอนิเตอร์ PSI แทนเหตุการณ์ vmpressure ให้กำหนดคอนฟิกคุณสมบัติ ro.lmk.use_psi ค่าดีฟอลต์คือ true ทำให้ PSI มอนิเตอร์กลไกเริ่มต้นของการตรวจจับแรงดันหน่วยความจำสำหรับ lmkd เนื่องจากมอนิเตอร์ PSI ต้องการการสนับสนุนเคอร์เนล เคอร์เนลจึงต้องรวมแพตช์ PSI backport และคอมไพล์ด้วยการเปิดใช้งานการรองรับ PSI ( CONFIG_PSI=y )

ข้อเสียของไดรเวอร์ LMK ในเคอร์เนล

Android เลิกใช้ไดรเวอร์ LMK เนื่องจากปัญหาหลายประการ ได้แก่:

  • อุปกรณ์ที่มี RAM ต่ำต้องได้รับการปรับแต่งอย่างจริงจัง และถึงกระนั้นก็ยังทำงานได้ไม่ดีกับปริมาณงานที่มีเพจแคชที่แอ็คทีฟสำรองไฟล์ขนาดใหญ่ ผลงานที่ย่ำแย่ส่งผลให้เกิดการฟาดฟันและไม่มีการสังหาร
  • ไดรเวอร์เคอร์เนล LMK อาศัยขีดจำกัดหน่วยความจำฟรี ไม่มีการปรับขนาดตามแรงดันหน่วยความจำ
  • เนื่องจากความแข็งแกร่งของการออกแบบ พันธมิตรจึงมักจะปรับแต่งไดรเวอร์เพื่อให้ทำงานบนอุปกรณ์ของพวกเขาได้
  • ไดรเวอร์ LMK เชื่อมต่อกับ Slab Shrinker API ซึ่งไม่ได้ออกแบบมาสำหรับการใช้งานหนัก เช่น การค้นหาเป้าหมายและการฆ่า ซึ่งทำให้กระบวนการ vmscan ช้าลง

Userspace lmkd

userspace lmkd ใช้ฟังก์ชันเดียวกันกับไดรเวอร์ในเคอร์เนล แต่ใช้กลไกเคอร์เนลที่มีอยู่เพื่อตรวจจับและประเมินความดันหน่วยความจำ กลไกดังกล่าวรวมถึงการใช้เหตุการณ์ vmpressure ที่สร้างเคอร์เนลหรือตัวตรวจสอบข้อมูลแผงข้อมูลแรงดัน (PSI) เพื่อรับการแจ้งเตือนเกี่ยวกับระดับความดันหน่วยความจำ และใช้คุณสมบัติของหน่วยความจำ cgroup เพื่อจำกัดทรัพยากรหน่วยความจำที่จัดสรรให้กับแต่ละกระบวนการตามความสำคัญของกระบวนการ

การใช้พื้นที่ผู้ใช้ lmkd ใน Android 10

ใน Android 9 และใหม่กว่า userspace lmkd จะเปิดใช้งานหากตรวจไม่พบไดรเวอร์ LMK ในเคอร์เนล เนื่องจาก userspace lmkd ต้องการการสนับสนุนเคอร์เนลสำหรับ cgroups หน่วยความจำ เคอร์เนลต้องถูกคอมไพล์ด้วยการตั้งค่าคอนฟิกูเรชันต่อไปนี้:

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

กลยุทธ์การฆ่า

Userspace lmkd รองรับกลยุทธ์การฆ่าตามเหตุการณ์ vmpressure หรือการมอนิเตอร์ PSI ความรุนแรง และคำแนะนำอื่นๆ เช่น การใช้สวอป กลยุทธ์การฆ่านั้นแตกต่างกันระหว่างอุปกรณ์ที่มีหน่วยความจำต่ำและอุปกรณ์ประสิทธิภาพสูง:

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

คุณสามารถกำหนดค่ากลยุทธ์การฆ่าโดยใช้คุณสมบัติ ro.config.low_ram สำหรับรายละเอียด โปรดดู การกำหนดค่าแรมต่ำ

Userspace lmkd ยังสนับสนุนโหมดดั้งเดิมซึ่งจะทำการตัดสินใจฆ่าโดยใช้กลยุทธ์เดียวกับไดรเวอร์ LMK ในเคอร์เนล (นั่นคือขีดจำกัดหน่วยความจำว่างและแคชไฟล์) หากต้องการเปิดใช้งานโหมดดั้งเดิม ให้ตั้งค่าคุณสมบัติ ro.lmk.use_minfree_levels true

กำลังกำหนดค่า lmkd

กำหนดค่า lmkd สำหรับอุปกรณ์เฉพาะโดยใช้คุณสมบัติต่อไปนี้

คุณสมบัติ ใช้ ค่าเริ่มต้น
ro.config.low_ram ระบุว่าอุปกรณ์นั้นเป็นอุปกรณ์ที่มีแรมต่ำหรือประสิทธิภาพสูง false
ro.lmk.use_psi ใช้มอนิเตอร์ PSI (แทนเหตุการณ์ vmpressure ) true
ro.lmk.use_minfree_levels ใช้ขีดจำกัดหน่วยความจำว่างและแคชไฟล์สำหรับการตัดสินใจฆ่ากระบวนการ (นั่นคือ ตรงกับฟังก์ชันการทำงานของไดรเวอร์ LMK ในเคอร์เนล) false
ro.lmk.low คะแนน oom_adj ขั้นต่ำสำหรับกระบวนการที่มีสิทธิ์ถูกฆ่าที่ระดับ vmpressure ต่ำ 1001
(พิการ)
ro.lmk.medium คะแนน oom_adj ขั้นต่ำสำหรับกระบวนการที่มีสิทธิ์ถูกฆ่าที่ระดับ vmpressure ปานกลาง 800
(บริการแคชหรือไม่จำเป็น)
ro.lmk.critical คะแนน oom_adj ขั้นต่ำสำหรับกระบวนการที่มีสิทธิ์ถูกฆ่าที่ระดับ vmpressure วิกฤต 0
(กระบวนการใดๆ)
ro.lmk.critical_upgrade เปิดใช้งานการอัปเกรดเป็นระดับวิกฤต false
ro.lmk.upgrade_pressure mem_pressure สูงสุดที่ระดับได้รับการอัพเกรดเนื่องจากระบบสลับกันมากเกินไป 100
(พิการ)
ro.lmk.downgrade_pressure mem_pressure ขั้นต่ำที่เหตุการณ์ vmpressure ถูกละเว้น เนื่องจากหน่วยความจำที่ว่างเพียงพอยังคงมีอยู่ 100
(พิการ)
ro.lmk.kill_heaviest_task ฆ่างานที่มีสิทธิ์มากที่สุด (การตัดสินใจที่ดีที่สุด) กับงานที่มีสิทธิ์ (การตัดสินใจที่รวดเร็ว) true
ro.lmk.kill_timeout_ms ระยะเวลาเป็นมิลลิวินาทีหลังจากการฆ่าเมื่อไม่มีการฆ่าเพิ่มเติม 0
(พิการ)
ro.lmk.debug เปิดใช้งานบันทึกการดีบัก lmkd false

ตัวอย่างการกำหนดค่าอุปกรณ์:

PRODUCT_PROPERTY_OVERRIDES += \
    ro.lmk.low=1001 \
    ro.lmk.medium=800 \
    ro.lmk.critical=0 \
    ro.lmk.critical_upgrade=false \
    ro.lmk.upgrade_pressure=100 \
    ro.lmk.downgrade_pressure=100 \
    ro.lmk.kill_heaviest_task=true

Userspace lmkd ใน Android 11

Android 11 ปรับปรุง lmkd โดยแนะนำกลยุทธ์การฆ่าใหม่ กลยุทธ์การฆ่าใช้กลไก PSI สำหรับการตรวจจับแรงดันหน่วยความจำที่นำมาใช้ใน Android 10 lmkd ในบัญชี Android 11 สำหรับระดับการใช้ทรัพยากรหน่วยความจำและการฟาดฟันเพื่อป้องกันความอดอยากในหน่วยความจำและการเสื่อมประสิทธิภาพ กลยุทธ์การฆ่านี้มาแทนที่กลยุทธ์ก่อนหน้านี้ และสามารถใช้ได้กับทั้งอุปกรณ์ประสิทธิภาพสูงและ RAM ต่ำ (Android Go)

ข้อกำหนดเคอร์เนล

สำหรับอุปกรณ์ Android 11 lmkd ต้องการคุณสมบัติเคอร์เนลต่อไปนี้:

  • รวมแพตช์ PSI และเปิดใช้งาน PSI (แบ็คพอร์ตมีให้ในเคอร์เนลทั่วไปของ Android 4.9, 4.14 และ 4.19)
  • รวมแพตช์สนับสนุน PIDFD (แบ็คพอร์ตมีให้ในเคอร์เนลทั่วไปของ Android 4.9, 4.14 และ 4.19)
  • สำหรับอุปกรณ์ที่มี RAM ต่ำ ให้รวมกลุ่มหน่วยความจำด้วย

เคอร์เนลต้องถูกคอมไพล์ด้วยการตั้งค่าคอนฟิกูเรชันต่อไปนี้:

CONFIG_PSI=y

การกำหนดค่า lmkd ใน Android 11

กลยุทธ์การฆ่าหน่วยความจำใน Android 11 รองรับปุ่มปรับแต่งและค่าเริ่มต้นตามรายการด้านล่าง คุณสมบัติเหล่านี้ทำงานได้ทั้งบนอุปกรณ์ประสิทธิภาพสูงและ RAM ต่ำ

คุณสมบัติ ใช้ ค่าเริ่มต้น
ประสิทธิภาพสูง RAM ต่ำ
ro.lmk.psi_partial_stall_ms เกณฑ์การหยุดทำงานของ PSI บางส่วนในหน่วยมิลลิวินาที สำหรับการทริกเกอร์การแจ้งเตือนหน่วยความจำเหลือน้อย หากอุปกรณ์ได้รับการแจ้งเตือนแรงดันหน่วยความจำช้าเกินไป ให้ลดค่านี้เพื่อทริกเกอร์การแจ้งเตือนก่อนหน้า หากการแจ้งเตือนแรงดันหน่วยความจำกระตุ้นโดยไม่จำเป็น ให้เพิ่มค่านี้เพื่อทำให้อุปกรณ์ไวต่อสัญญาณรบกวนน้อยลง 70 200
ro.lmk.psi_complete_stall_ms เกณฑ์การหยุดทำงานของ PSI ที่สมบูรณ์ หน่วยเป็นมิลลิวินาที สำหรับการทริกเกอร์การแจ้งเตือนหน่วยความจำที่สำคัญ หากอุปกรณ์ได้รับการแจ้งเตือนแรงดันหน่วยความจำที่สำคัญช้าเกินไป ให้ลดค่านี้เพื่อทริกเกอร์การแจ้งเตือนก่อนหน้า หากการแจ้งเตือนแรงดันหน่วยความจำที่สำคัญกระตุ้นโดยไม่จำเป็น ให้เพิ่มค่านี้เพื่อทำให้อุปกรณ์ไวต่อสัญญาณรบกวนน้อยลง 700
ro.lmk.thrashing_limit จำนวนสูงสุดของชุดการทำงานเริ่มต้นใหม่เป็นเปอร์เซ็นต์ของขนาดเพจแคชที่สำรองไฟล์ทั้งหมด ค่ารีฟอลต์ของ Workingset ที่สูงกว่าค่านี้หมายความว่าระบบจะถือว่าระบบกำลังบีบอัด pagecache หากประสิทธิภาพของอุปกรณ์ได้รับผลกระทบระหว่างแรงดันหน่วยความจำ ให้ลดค่าลงเพื่อจำกัดการฟาด หากประสิทธิภาพของอุปกรณ์ถูกฆ่าโดยไม่จำเป็นด้วยเหตุผลการฟาดฟัน ให้เพิ่มค่าเพื่อให้มีการฟาดมากขึ้น 100 30
ro.lmk.thrashing_limit_decay การสลายตัวของ Thrashing Threshold แสดงเป็นเปอร์เซ็นต์ของเกณฑ์เดิมที่ใช้ในการลด Thrashing Threshold เมื่อระบบไม่ฟื้นตัว แม้จะฆ่าไปแล้วก็ตาม หากการฟาดฟันอย่างต่อเนื่องทำให้เกิดการฆ่าโดยไม่จำเป็น ให้ลดค่าลง หากการตอบสนองต่อการฟาดต่อเนื่องหลังจากการฆ่าช้าเกินไป ให้เพิ่มค่า 10 50
ro.lmk.swap_util_max จำนวนหน่วยความจำที่สลับสูงสุดเป็นเปอร์เซ็นต์ของหน่วยความจำที่สลับได้ทั้งหมด เมื่อหน่วยความจำที่สลับเพิ่มขึ้นเกินขีดจำกัดนี้ หมายความว่าระบบได้สลับหน่วยความจำที่สลับได้เกือบทั้งหมดและยังอยู่ภายใต้แรงกดดัน สิ่งนี้สามารถเกิดขึ้นได้เมื่อการจัดสรรที่ไม่สามารถสับเปลี่ยนได้ทำให้เกิดแรงกดดันในหน่วยความจำซึ่งไม่สามารถบรรเทาได้ด้วยการแลกเปลี่ยนเนื่องจากหน่วยความจำแบบถอดเปลี่ยนได้ส่วนใหญ่ถูกสลับออกแล้ว ค่าเริ่มต้นคือ 100 ซึ่งปิดใช้งานการตรวจสอบนี้อย่างมีประสิทธิภาพ หากประสิทธิภาพของอุปกรณ์ได้รับผลกระทบระหว่างแรงดันหน่วยความจำในขณะที่การใช้งานการสลับสูง และระดับการสลับฟรีไม่ลดลงเหลือ ro.lmk.swap_free_low_percentage ให้ลดค่าเพื่อจำกัดการใช้การสลับ 100 100

ปุ่มปรับเสียงแบบเก่าต่อไปนี้ยังใช้งานได้กับกลยุทธ์การฆ่าแบบใหม่

คุณสมบัติ ใช้ ค่าเริ่มต้น
ประสิทธิภาพสูง RAM ต่ำ
ro.lmk.swap_free_low_percentage ระดับของการแลกเปลี่ยนฟรีเป็นเปอร์เซ็นต์ของพื้นที่สว็อปทั้งหมด `lmkd' ใช้ค่านี้เป็นเกณฑ์เมื่อพิจารณาว่าระบบขาดพื้นที่สว็อป หาก `lmkd' ฆ่าในขณะที่มีที่ว่างในการแลกเปลี่ยนมากเกินไป ให้ลดเปอร์เซ็นต์ หากการฆ่า `lmkd' เกิดขึ้นช้าเกินไป ทำให้การฆ่า OOM เกิดขึ้นได้ ให้เพิ่มเปอร์เซ็นต์ 20 10
ro.lmk.debug สิ่งนี้จะเปิดใช้งานบันทึกการดีบัก `lmkd' เปิดใช้งานการดีบักขณะปรับแต่ง false