ดีมอนนักฆ่าที่มีหน่วยความจำต่ำ

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

เกี่ยวกับภาระของหน่วยความจํา

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

ที่ผ่านมา Android ได้ตรวจสอบแรงกดดันของหน่วยความจำของระบบโดยใช้ไดรเวอร์ Low Memory Killer (LMK) ในเคอร์เนล ซึ่งเป็นกลไกที่เข้มงวดซึ่งขึ้นอยู่กับค่าที่กำหนดไว้อย่างตายตัว ตั้งแต่เคอร์เนล 4.12 ระบบจะนำไดรเวอร์ LMK ออกจากเคอร์เนลอัปสตรีม และพื้นที่ผู้ใช้ lmkd จะทำหน้าที่ตรวจสอบหน่วยความจำและฆ่ากระบวนการ

ข้อมูลหยุดอัดแรงดัน

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

สัญญาณ PSI Monitor เทียบกับ 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 ต่ำต้องได้รับการปรับแต่งอย่างหนักหน่วง และแม้จะปรับแต่งแล้วก็ยังทำงานได้ไม่ดีกับเวิร์กโหลดที่มี PageCache ที่ใช้งานอยู่ซึ่งสำรองข้อมูลไว้ในไฟล์ขนาดใหญ่ ประสิทธิภาพที่ต่ำส่งผลให้เกิดการสับเปลี่ยนและไม่มีการสังหาร
  • ไดรเวอร์เคอร์เนล LMK ใช้ขีดจำกัดของหน่วยความจำว่าง โดยไม่มีการปรับขนาดตามความดันหน่วยความจำ
  • เนื่องจากการออกแบบมีความเข้มงวด พาร์ทเนอร์จึงมักปรับแต่งไดรเวอร์เพื่อให้ทำงานในอุปกรณ์ของตนได้
  • คนขับรถของ LMK ใช้ประโยชน์จาก Slab Srinker API ซึ่งไม่ได้ออกแบบมาเพื่อ ปฏิบัติการหนัก เช่น การค้นหาเป้าหมายและการฆ่าเป้าหมาย ซึ่งทำให้กระบวนการ vmscan ช้าลง

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

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

ใช้ lmkd ใน Userspace ของ Android 10

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

CONFIG_ANDROID_LOW_MEMORY_KILLER=n
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y

ปิดใช้กลยุทธ์

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

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

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

พื้นที่ผู้ใช้ 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 ฆ่างานที่หนักที่สุดที่มีสิทธิ์ (การตัดสินใจที่ดีที่สุด) เทียบกับงานที่อาจมีสิทธิ์ (การตัดสินใจที่รวดเร็ว) false
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

lmkd ใน Userspace ของ 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 ต่ำ ให้ใส่ cgroups หน่วยความจำ

ต้องคอมไพล์เคอร์เนลด้วยการตั้งค่าการกําหนดค่าต่อไปนี้

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 จำนวนสูงสุดของชุดทำงานที่รีเซ็ตเป็นค่าเริ่มต้นเป็นเปอร์เซ็นต์ของขนาดแคชหน้าเว็บที่สำรองข้อมูลไว้ในไฟล์ทั้งหมด การรีเซ็ต Working Set ที่สูงกว่าค่านี้หมายความว่าระบบจะถือว่ามีการเรียกใช้แคชหน้าเว็บมากเกินไป หากประสิทธิภาพของอุปกรณ์ได้รับผลกระทบในระหว่างที่หน่วยความจํามีการใช้งานสูง ให้ลดค่าเพื่อจำกัดการกระชาก หากระบบหยุดการทำงานของอุปกรณ์โดยไม่จำเป็นด้วยเหตุผลของการทับซ้อน ให้เพิ่มค่าเพื่อให้มีการขว้างที่มากขึ้น 100 30
ro.lmk.thrashing_limit_decay การลดลงของเกณฑ์การถล่มที่แสดงเป็นเปอร์เซ็นต์ของเกณฑ์เดิมที่ใช้เพื่อลดเกณฑ์เมื่อระบบไม่ฟื้นตัว แม้ว่าจะมีการสิ้นสุดกระบวนการแล้วก็ตาม หากการทํางานหนักอย่างต่อเนื่องทําให้เกิดกระบวนการที่สิ้นเปลืองโดยไม่จําเป็น ให้ลดค่า หากการตอบสนองต่อการสับเปลี่ยนอย่างต่อเนื่องหลังจากการฆ่าช้าเกินไป ให้เพิ่มค่า 10 50
ro.lmk.swap_util_max จำนวนหน่วยความจำที่แลกเปลี่ยนสูงสุดคิดเป็นเปอร์เซ็นต์ของหน่วยความจำทั้งหมดที่แลกเปลี่ยนได้ เมื่อหน่วยความจำที่ย้ายไปอยู่ในฮาร์ดดิสก์มีจำนวนมากกว่าขีดจำกัดนี้ หมายความว่าระบบได้ย้ายหน่วยความจำที่ย้ายได้ส่วนใหญ่ไปไว้ในฮาร์ดดิสก์และยังคงมีภาระงานอยู่ กรณีนี้อาจเกิดขึ้นเมื่อการจัดสรรที่ย้ายไม่ได้สร้างแรงกดดันของหน่วยความจำซึ่งไม่สามารถบรรเทาด้วยการสลับหน่วยความจำเนื่องจากหน่วยความจำส่วนใหญ่ที่ย้ายได้ถูกสลับออกไปแล้ว ค่าเริ่มต้นคือ 100 ซึ่งจะปิดใช้การตรวจสอบนี้ หากประสิทธิภาพของอุปกรณ์ได้รับผลกระทบระหว่างที่หน่วยความจํามีการใช้งานสูงและระดับ Swap ว่างไม่ได้ลดลงถึง ro.lmk.swap_free_low_percentage ให้ลดค่าเพื่อจํากัดการใช้งาน Swap 100 100

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

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