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

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

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

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

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

ข้อมูลแผงแรงดัน

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

จอภาพ PSI เทียบกับสัญญาณ vmpressure

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

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

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

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

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

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

พื้นที่ผู้ใช้ lmkd

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

การใช้ userspace lmkd ใน Android 10

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

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

ฆ่ากลยุทธ์

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

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

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

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

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

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

คุณสมบัติ ใช้ ค่าเริ่มต้น
ro.config.low_ram ระบุว่าอุปกรณ์นั้นเป็นอุปกรณ์ที่มี 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 (backport มีอยู่ในเคอร์เนลทั่วไปของ Android 4.9, 4.14 และ 4.19)
  • รวมแพทช์สนับสนุน PIDFD (backport มีอยู่ในเคอร์เนลทั่วไปของ Android 4.9, 4.14 และ 4.19)
  • สำหรับอุปกรณ์ที่มี RAM ต่ำ ให้รวมกลุ่มหน่วยความจำด้วย

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

CONFIG_PSI=y

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

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

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

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

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