กระบวนการเบื้องหลังสำหรับจัดการหน่วยความจำต่ำของ 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 |