การจัดสรรหน่วยความจำในกระบวนการต่างๆ

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

หน้านี้จะอธิบายข้อมูลพื้นฐานเกี่ยวกับวิธีที่ Android จัดสรรหน่วยความจำให้กับระบบและแอปพลิเคชันของผู้ใช้ รวมถึงอธิบายวิธีที่ระบบปฏิบัติการตอบสนองต่อสถานการณ์ที่หน่วยความจำเหลือน้อย

ประเภทของหน่วยความจำ

อุปกรณ์ Android มีหน่วยความจำ 3 ประเภท ได้แก่ RAM, zRAM และพื้นที่เก็บข้อมูล โปรดทราบว่าทั้ง CPU และ GPU เข้าถึง RAM เดียวกัน

ประเภทของความทรงจำ

รูปที่ 1 ประเภทของหน่วยความจำ - RAM, zRAM และพื้นที่เก็บข้อมูล

  • RAM เป็นหน่วยความจำประเภทที่เร็วที่สุด แต่โดยปกติจะมีขนาดจำกัด อุปกรณ์ระดับไฮเอนด์มักจะมี RAM มากที่สุด

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

  • พื้นที่เก็บข้อมูลมีข้อมูลถาวรทั้งหมด เช่น ระบบไฟล์และโค้ดออบเจ็กต์ที่รวมไว้สำหรับแอป ไลบรารี และแพลตฟอร์มทั้งหมด พื้นที่เก็บข้อมูลมีความจุมากกว่าหน่วยความจำอีก 2 ประเภทมาก ใน Android ระบบจะไม่ใช้พื้นที่เก็บข้อมูลสำหรับพื้นที่สวอปเหมือนกับการใช้งาน Linux อื่นๆ เนื่องจากมีการเขียนข้อมูลบ่อยๆ อาจทำให้หน่วยความจำนี้เสื่อมสภาพและทำให้อายุการใช้งานของสื่อบันทึกลดลง

หน้าหน่วยความจำ

RAM จะแบ่งออกเป็น หน้า โดยปกติแล้วแต่ละหน้าจะมีหน่วยความจำ 4KB

หน้าจะถือว่าเป็น ว่าง หรือ ใช้งาน หน้าว่างคือ RAM ที่ไม่ได้ใช้ หน้าใช้งานคือ RAM ที่ระบบกำลังใช้งานอยู่ และจะจัดกลุ่มเป็นหมวดหมู่ต่อไปนี้

  • แคช: หน่วยความจำที่สำรองด้วยไฟล์ในพื้นที่เก็บข้อมูล (เช่น โค้ดหรือไฟล์ที่แมปกับหน่วยความจำ) หน่วยความจำแคชมี 2 ประเภท ได้แก่
    • ส่วนตัว: เป็นของกระบวนการเดียวและไม่ได้แชร์
      • สะอาด: สำเนาไฟล์ที่ไม่ได้แก้ไขในพื้นที่เก็บข้อมูล ซึ่ง kswapd สามารถลบได้เพื่อเพิ่มหน่วยความจำที่ว่าง
      • มีการแก้ไข: สำเนาไฟล์ที่แก้ไขแล้วในพื้นที่เก็บข้อมูล ซึ่ง kswapd สามารถย้ายไปหรือบีบอัดใน zRAM ได้เพื่อเพิ่มหน่วยความจำที่ว่าง
    • แชร์: ใช้โดยหลายกระบวนการ
      • สะอาด: สำเนาไฟล์ที่ไม่ได้แก้ไขในพื้นที่เก็บข้อมูล ซึ่ง kswapd สามารถลบได้เพื่อเพิ่มหน่วยความจำที่ว่าง
      • มีการแก้ไข: สำเนาไฟล์ที่แก้ไขแล้วในพื้นที่เก็บข้อมูล ซึ่งอนุญาตให้เขียนการเปลี่ยนแปลงกลับไปยังไฟล์ในพื้นที่เก็บข้อมูลเพื่อเพิ่มหน่วยความจำที่ว่างโดย kswapd หรือใช้ msync() หรือ munmap()
  • ไม่ระบุชื่อ: หน่วยความจำที่ไม่ได้ สำรองด้วยไฟล์ในพื้นที่เก็บข้อมูล (เช่น จัดสรรโดย mmap() โดยตั้งค่าแฟล็ก MAP_ANONYMOUS )
    • สกปรก: kswapd สามารถย้าย/บีบอัดใน zRAM ได้เพื่อเพิ่มหน่วยความจำที่ว่าง

สัดส่วนของหน้าว่างและหน้าใช้งานจะแตกต่างกันไปตามเวลาเนื่องจากระบบจัดการ RAM อย่างต่อเนื่อง แนวคิดที่แนะนำในส่วนนี้มีความสำคัญต่อการจัดการสถานการณ์ที่หน่วยความจำเหลือน้อย ส่วนถัดไปของเอกสารนี้จะอธิบายแนวคิดเหล่านี้โดยละเอียดมากขึ้น

การจัดการหน่วยความจำเหลือน้อย

Android มีกลไกหลัก 2 อย่างในการจัดการสถานการณ์ที่หน่วยความจำเหลือน้อย ได้แก่ เคอร์เนลสวอปดีมอนและตัวจัดการกระบวนการเมื่อหน่วยความจำเหลือน้อย

เคอร์เนลสวอปดีมอน

เคอร์เนลสวอปดีมอน (kswapd) เป็นส่วนหนึ่งของเคอร์เนล Linux และจะแปลงหน่วยความจำที่ใช้แล้วเป็นหน่วยความจำที่ว่าง Daemon จะทำงานเมื่อหน่วยความจำที่ว่างในอุปกรณ์เหลือน้อย เคอร์เนล Linux จะรักษาเกณฑ์หน่วยความจำที่ว่างเหลือน้อยและเหลือมาก เมื่อหน่วยความจำที่ว่างลดลงต่ำกว่าเกณฑ์ต่ำ kswapd จะเริ่มเรียกคืนหน่วยความจำ เมื่อหน่วยความจำที่ว่างถึงเกณฑ์สูง kswapd จะหยุดเรียกคืนหน่วยความจำ

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

ล้างหน้าเว็บที่สำรองข้อมูลไว้ในพื้นที่เก็บข้อมูลที่ลบไปแล้ว

รูปที่ 2 หน้าสะอาดที่สำรองด้วยพื้นที่เก็บข้อมูลถูกลบ

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

หากหน่วยความจำที่ว่างลดลงต่ำกว่าเกณฑ์ที่กำหนด ระบบจะเริ่มหยุดกระบวนการ

ย้ายหน้าที่มีการแก้ไขไปยัง zRAM และบีบอัด

รูปที่ 3 หน้าที่มีการแก้ไขถูกย้ายไปยัง zRAM และบีบอัด

ตัวจัดการกระบวนการเมื่อหน่วยความจำเหลือน้อย

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

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

กระบวนการของ Android คะแนนสูงจะอยู่ด้านบน

รูปที่ 4 กระบวนการของ Android โดยมีคะแนนสูงอยู่ด้านบนและคะแนนต่ำอยู่ด้านล่าง

คำอธิบายสำหรับหมวดหมู่ต่างๆ ในตารางด้านบนมีดังนี้

  • แอปที่ทำงานอยู่เบื้องหลัง: แอปที่เคยทำงานและไม่ได้ใช้งานอยู่ในปัจจุบัน LMK จะหยุดแอปที่ทำงานอยู่เบื้องหลังก่อน โดยเริ่มจากแอปที่มี oom_adj_score สูงที่สุด

  • แอปก่อนหน้า: แอปที่ทำงานอยู่เบื้องหลังซึ่งใช้ล่าสุด แอปก่อนหน้ามีความสำคัญสูงกว่า (คะแนนต่ำกว่า) แอปที่ทำงานอยู่เบื้องหลัง เนื่องจากผู้ใช้มีแนวโน้มที่จะสลับไปใช้แอปก่อนหน้ามากกว่าแอปที่ทำงานอยู่เบื้องหลัง

  • แอป Home: นี่คือแอปตัวเรียกใช้ การหยุดแอปนี้จะทำให้วอลเปเปอร์หายไป

  • บริการ: แอปพลิเคชันจะเริ่มบริการ และบริการอาจรวมถึงการซิงค์หรือการอัปโหลดไปยังระบบคลาวด์

  • แอปที่รับรู้ได้: แอปที่ไม่ได้ทำงานอยู่เบื้องหน้าซึ่งผู้ใช้รับรู้ได้ในบางวิธี เช่น การเรียกใช้กระบวนการค้นหาที่แสดง UI ขนาดเล็กหรือการฟังเพลง

  • แอปที่ทำงานอยู่เบื้องหน้า: แอปที่กำลังใช้งานอยู่ การหยุดแอปที่ทำงานอยู่เบื้องหน้าจะมีลักษณะเหมือนแอปพลิเคชันขัดข้อง ซึ่งอาจบ่งบอกให้ผู้ใช้ทราบว่ามีบางอย่างผิดปกติกับอุปกรณ์

  • ถาวร (บริการ): บริการเหล่านี้เป็นบริการหลักสำหรับอุปกรณ์ เช่น โทรศัพท์และ Wi-Fi

  • ระบบ: กระบวนการของระบบ เมื่อกระบวนการเหล่านี้ถูกหยุด โทรศัพท์อาจปรากฏขึ้นเพื่อรีบูต

  • เนทีฟ: กระบวนการระดับต่ำมากที่ระบบใช้ (เช่น kswapd)

ผู้ผลิตอุปกรณ์สามารถเปลี่ยนลักษณะการทำงานของ LMK ได้

การคำนวณหน่วยความจำที่ใช้

เคอร์เนลจะติดตามหน้าหน่วยความจำทั้งหมดในระบบ

หน้าที่กระบวนการต่างๆ ใช้

รูปที่ 5 หน้าต่างๆ ที่กระบวนการต่างๆ ใช้

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

หน้าเว็บที่แชร์โดย 2 แอป

รูปที่ 6 หน้าต่างๆ ที่แชร์โดยแอป 2 แอป (ตรงกลาง)

ระบบอาจใช้เมตริกใดเมตริกหนึ่งต่อไปนี้เพื่อกำหนดหน่วยความจำที่ใช้สำหรับแอปพลิเคชัน

  • ขนาดชุดที่อยู่ในหน่วยความจำ (RSS): จำนวนหน้าแชร์และหน้าที่ไม่แชร์ที่แอปใช้
  • ขนาดชุดตามสัดส่วน (PSS): จำนวนหน้าที่ไม่แชร์ที่แอปใช้และการกระจายหน้าแชร์อย่างเท่าเทียมกัน (เช่น หาก 3 กระบวนการแชร์ 3MB แต่ละกระบวนการจะได้รับ 1MB ใน PSS)
  • ขนาดชุดที่ไม่ซ้ำกัน (USS): จำนวนหน้าที่ไม่แชร์ที่แอปใช้ (ไม่รวมหน้าแชร์)

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

แหล่งข้อมูลเพิ่มเติม