Latest article
Home >> Linux >> Linux Memory Management
Linux Memory Management

Linux Memory Management

เคยสงสัยกันหรือไม่ว่า

  • การจัดการ memory ของ Linux นั้น ทำงานอย่างไร
  • page คืออะไร 
  • ทำใมมี process ชื่อแปลกๆ โผล่มาทำงานในเครื่องของเรา เช่น kscand, kswapd, bdflush
  • Buffer ต่างจาก Cache อย่างไร

วันนี้เราจะไขข้อสงสัยกันให้จบสิ้นไปเลย


Structure of Linux Memory Management

โดยปกติ os. จะทำหน้าที่ในการจัดการ memory ให้กับ application โดยจะแบ่ง memory ออกเป็นหลายๆ ส่วน เช่น

  • virtual memory ==> เอา harddisk หรืออุปกรณ์อื่นที่ไม่ใช่ ram มาใช้เป็น memory
  • protected memory ==> เข้าถึงได้เฉพาะ process ที่เป็นเจ้าของเท่านั้น
  • shared memory => เข้าถึงได้ทั่วไป

การจัดการ memory นั้นเป็นหน้าที่ของอุปกรณ์ที่เรียกว่า Memory Management Unit (MMU) *เป็น hardware* โดย

  • MMU จะทำหน้าที่แปลง physical memory address ให้เป็น alias address เพื่อให้ os. เอาไปใช้งาน
  • MMU จะทำหน้าที่ request a page fault interrupt เมื่อ CPU ต้องการ access memory ส่วนที่มันไม่มีสิทธิ์
  • MMU จะใช้พื้นที่ memory ส่วนหนึ่งเพื่อแปลง virtual address ไปเป็น physical address (table lookup)

อย่างไรก็ตาม เนื่องจาก MMU นั้นเป็นอุปกรณ์ที่ทำงานในระดับ Processor และบาง processor ก็ไม่ได้มีอุปกรณ์นี้ติดมาด้วย จึงมี community กลุ่ม ucLinux Distribution (Embedded Linux/Micro Controller Project) แก้ไขให้สามารถใช้งาน single namespace ได้ ซึ่งทำให้ Linux สามารถใช้งานได้หลากหลาย Processor มากกว่า

Page

เพื่อให้เข้าใจการทำงานของ memory management มากขึ้น เราจะไปทำความเข้าใจหน่วยย่อยที่สุดของ memory คือ page

  • Page คือ non-overlapping region of contiguous memory แปลง่ายๆ คือ ผืน memory ที่อยู่ติดๆ กัน และไม่เกยซ้ำกัน (ภาษาอังกฤษน่าจะเข้าใจง่ายกว่านะ)
  • Physical memory ทั้งหมดจะถูกจัดให้อยู่ในรูป Page ไปจนถึงสุดเขตของ kernel’s boot process
  • ขนาดของ Page ขึ้นกับสถาปัตยกรรมของ CPU โดยส่วนใหญ่จะกำหนดขนาดของ page ไว้สองขนาด
    • ค่า default size ของ page คือ 4069 Byte (4KB)
    • วิธีตรวจสอบ linux page size (หน่วยเป็น byte)
      $ getconf PAGESIZE

ข้อสังเกตุคือ ถ้าเราต้องการเก็บข้อมูลที่มีขนาดน้อยกว่า Page size จะทำได้หลายวิธี เช่น

  • in the kernel: ใช้วิธีการ allocate small object โดยใช้ slab collector (มันคืออะไรฟ้ะ)
  • kmalloc: allocate a block ที่อยู่ใกล้ block ที่ขนาดใหญ่ที่สุด (ฟังดูงงๆ )
  • user mode: ใช้ heap management function ใน standard C library
  • หรือจะเขียน heap manager ทำงาน ontop Linux Kernel system call เองเลยก็ได้

เพื่อให้การทำงานกับส่วน MMU ง่าย จึงแบ่งการ allocate, release memory ออกเป็น 3 ระดับคือ

  1. The Slab Allocator
  2. The Zone Allocator
  3. The Buddy Allocator

ใน Linux โดยส่วนใหญ่จะใช้งาน GCC Standard C Library ซึ่งเรียกว่า glibc (ทั้งโดยตรงและทางอ้อม)

Note: ความหมายของ VM ในที่นี่คือ Virtual Memory นะ ไม่ใช่ Virtual Machine


Kernel Mode Memory Management Services

Zone Buddy Allocator

มีหน้าที่

  • ในการจัด page allocation ทั้งระบบ
  • จัดการ list ของ physical address ที่อยู่ติดๆ กัน เพื่อ map เข้า MMU Table
  • รับจัดการแปลง virtual address –> physical address เมื่อ kernel ส่ง request เข้ามา (หน้าที่การแปลง physical address –> virtual address ถูกจัดการใน level ที่สูงกว่า VM)

ชื่อ Buddy ได้มาจาก algorithm ในการทำงานของมัน

  • Buddy Allocator จะรวม physical page ใน RAM มาเป็น list
  • List จะเริ่มตั้งแต่หมายเลข 2n เช่น 0, 1, 2, 4 ไปเรื่อยๆ จนถึง MAX_ORDER (define ไว้ใน linux/mmzone.h)
  • โดยในแต่ละ entry จะประกอบไปด้วยคู่ของ page ที่มีขนาดเท่ากับ n (สามารถมีได้มากกว่า 1 คู่) ตามภาพประกอบด้านล่าง
  • กรณีที่ไม่มี entry ว่าง (physical page) ใน list ที่ร้องขอมา
    • list ที่อยู่ด้านบนจะถูกแบ่งครึ่ง ครึ่งแรกจะถูกส่งกลับไปให้ requester
    • ส่วนครึ่งทีสองจะถูกส่งไปรวมกับ list ที่อยู่ด้านล่าง
    • ตัวอย่าง เช่น  requester ร้องขอ page ว่างขนาด 4 page (4×4096 KB) และในขณะนั้น list ของ n=2 (2^2 = 4) ไม่ว่าง (มีคนอื่นใช้งานแล้ว)
      • Buddy Allocator จะเข้าไปส่ง memory address  ของ 2^3 โดยแบ่งครึ่งส่งไปให้ requester ตามขนาดทีร้องขอ (4 page) ส่วน 4 page ที่เหลือจะ append ไปกับ list ของ n=2
  • กรณีที่มีการคืน memory กลับมา Buddy Allocator ก็จะทำงานกลับกัน

นอกจากนี้ Buddy Allocator ยังทำงานร่วมกับ kswapd และ bdflush ซึ่งเป็น Process ที่ดูแลเกี่ยวกับ swap อีกด้วย

Buddy Allocator ยังทำหน้าที่เกี่ยวกับการจัดการ memory zone ด้วย ซึ่งแต่ละ zone ก็จะมีหน้าที่คนละอย่างกัน มีด้วยกัน 3 zone คือ

  • DMA
    • เป็น memory ส่วน 16MB แรก กันไว้สำหรับ legacy device เท่านั้น
  • NORMAL
    • เป็น memory ส่วนหลังจาก 16 MB – 1GB แรก
    • ใช้โดย Kernel, systems และ user space allocation
  • HIGHMEM
    • เป็น memory ส่วนเหนือจาก 1GB เป็นต้นไป
    • ใช้สำหรับ system allocation เช่น file system buffers, user space allocation

Slab Allocator (an object-caching kernel memory allocator)

ทำหน้าที่

  • เป็นตัวเชื่อมต่อกับ Buddy Allacator ทำให้ application ที่ต้องการร้องขอ memory ที่มีขนาดแตกต่างจาก Page size (4KB) ทำงานได้ง่ายขึ้น
  • ช่วยให้ kernel component สามารถสร้าง cache ของ memory object ในขนาดที่ต้องการได้
    • ตัวอย่าง object เช่น inode_cache, dentry_cache, buffer_head, vm_area_struct
    • เราสามารถ request การจัดสรร memory สำหรับ object ตามขนาดที่ต้องการได้ โดยใช้ kmalloc
  • ทำหน้าที่จัดเก็บ cache’s object ลงบน page ให้ได้มากที่สุด และทำหน้าที่ monitor ว่า object ใหนว่างหรือถูกใช้งานไปแล้ว
  • กรณีที่มีการร้องขอ memory มาและไม่มีพื้นที่ว่างแล้ว Slab จะติดต่อกับ Buddy เพื่อขอพื้นที่ Page เพิ่มเติม
  • ด้วยรูปแบบการทำงานแบบนี้ จะทำให้การใช้งาน memory เป็นเป็นอย่างมีประสิทธิภาพและไม่จำเป็นต้องมี memory management code ส่วนอื่นโดยไม่จำเป็น
  • Slab จะจัดสรร memory เฉพาะใน zone DMA และ NORMAL เท่านั้น

Kernel Thread

component อื่นๆ ใน VM subsystem ก็คือ kscand, kswapd, kupdated, bdflush โดย component เหล่านี้ มีหน้าที่ในการจัดการการใช้งาน memory

  • ทุกๆ page ใน memory จะมี state ของมัน (ดูรายละเอียดใน The Life of a Page)
  • โดยทั่วไปแล้ว task ใน kernel จะทำหน้าที่ตรวจสอบ RAM อย่างสม่ำเสมอ เพื่อพยายามคืนพื้นที่ memory ให้สามารถนำไปใช้งานส่วนอื่นได้

The Life of a Page

Memory ที่ถูกจัดการโดย VM จะมี state ของมันเสมอ เพื่อช่วยให้ VM สามารถจัดการ memory ได้ง่ายและมีประสิทธิภาพ

State Machine

  • FREE
    • ตรงๆ คือ ว่างอยู่ พร้อมให้เอาไปใช้งาน
  • ACTIVE
    • Page ที่ถูก allocate โดย  Buddy Allocator จะเข้าสู่ state นี้
  • INACTIVE DIRTY
    • State นี้เป็นตัวบ่งบอกว่า Page ไม่ได้ถูกใช้งานแล้ว เป็นตัว candidate ที่จะถูกลบออกจาก main memory
    • kscand จะทำหน้าที่กวาดเช็คทุก page ใน memory ตรวจสอบระยะที่ข้อมูลใน page ถูกเรียกใช้งานครั้งสุดท้าย
      • ถ้า kscand พบว่า มีการเรียกใช้งานจาก process อื่น ภายหลังจากครั้งสุุดท้ายที่ kscand เข้ามาตรวจสอบ มันจะเพิ่มค่า counter เข้าไป
      • ถ้าไม่มีการเรียกใช้งานจาก process อื่น ภายหลังจากครั้งสุดท้ายที่ kscand เข้ามาตรวจสอบ มันจะลดค่า counter ลงไป
      • ถ้าค่า counter=zero ตัว kscand จะ set state ของ page เป็น INACTIVE DIRTY
  • INACTIVE LAUNDERED
    • มีเฉพาะ page ใน INACTIVE DIRTY เท่านั้น ที่จะเข้าสู่ INACTIVE LAUNDERED ได้
    • เมื่อเข้าสู่ state นี้ content ที่อยู่ใน page จะถูกย้ายลง disk
    • ในระหว่างที่รอ i/o  operation หากมี request access เข้ามา มันจะเปลี่ยนไปเป็น ACTIVE state ได้ทันที
    • หาก i/o operation แล้วเสร็จ PAGE จะถูกเปลี่ยน state เป็น INACTIVE CLEAN
  • INACTIVE CLEAN
    • Page ที่อยู่ใน state นี้ จะถูก deallocate กลายเป็น FREE และอนุญาตให้ถูกเขียนทับได้

 

หลังจากที่เข้าใจ State machine แล้ว ลอง cat /proc/meminfo ดูเพื่อดูว่า เราเข้าใจ parameter ต่างๆ ในไฟล์นี้ได้ดีขึ้นมากน้อยแค่ใหน


Tuning The VM

การแก้ไขค่าใน Linux VM สามารถทำได้ 2 ทางคือ

  • sysctl
    • แก้ไขได้ 2 รุปแบบคือ
      • /etc/sysctl.conf หลังจากแก้ไขแล้ว ให้รันคำสั่ง sysctl –p เพื่อให้การแก้ไขมีผล
      • ใช้คำสั่ง sysctl –w variable=value
        • ข้อควรระวังคือ การแก้ไขดังกล่าว มีผลทันที แต่หากเครื่อง reboot ค่านี้จะหายไป (ควรแก้ไข /etc/sysctl.conf สำหรับค่าที่ต้องการปรับถาวร)
    • ใช้คำสั่ง sysctl –a เพื่อดู parameter ที่ต้องการปรับ
  • proc file system
    • เป็น virtual file อยู่ที่ /proc/sys/vm
      • ตรวจสอบค่า ใช้ cat /proc/sys/vm/kswapd
      • แก้ไขค่าใช้ echo 511 31 7 > /proc/sys/vm/kswapd

buffers vs cached

เคยดูค่าที่ได้จากการรัน free หรือไม่ แล้วสงสัยหรือไม่ว่า buffers ต่างจาก cached อย่างไร

$ free
total used free shared buffers cached
Mem: 4040360 4012200 28160 0 176628 3571348
-/+ buffers/cache: 264224 3776136
Swap: 4200956 12184 4188772
$

  • Buffers คือ memory ที่ใช้ไปเพื่อเก็บ filesystem metadata
  • Cached คือ page (memory) ที่ใช้เก็บ contents ของไฟล์หรือ block device

Linux จะใช้ memory ที่มีอยู่เพื่อเป็นทั้ง buffers และ cached เพื่อความรวดเร็วในการเข้าถึงไฟล์ (ลด i/o operation) ถ้าหากมีโปรแกรมอื่นต้องการใช้พื้นที่ใน memory ตัว Linux VM จะจัดสรรพื้นให้ application เหล่านั้นเองโดยการลดพื้นที่ของ buffers หรือ cached ลง

bdflush

bdflush มีค่า parameter ทั้งหมด 9 ค่า แต่สามารถแก้ไขได้เพียง 6 ค่า ซึ่งค่าต่างๆ เหล่านี้มีผลต่ออัตราการ free page ของ buffer cache (เป็น subset ของ pagecache ซึ่งเก็บไฟล์ไว้ใน memory)

  • nfrac => bdflush จะทำงานเมื่อ percentage ของ dirty page ใน buffer cache มีปริมาณถึงค่าที่กำหนด
  • ndirty => ปริมาณสูงสุดของ dirty page ที่อยู่ใน buffer cache ที่จะถูก write ลง disk ในแต่ละครั้ง
  • interval => ปริมาณของ jiffies (10 ms period) เพื่อหน่วงการทำงานของ bdflush
  • age_buffer => ช่วงเวลาที่ข้อมูลจะถูกเก็บใน buffer จากนั้นจึงจะถูก flush ลง disk
  • nfract_syn => percentage ของ dirty page ใน buffer cache ที่เป็นตัวกำหนดว่าให้ write page ลง disk แทนการ write page ลงบน memory
  • nfract_stop_bdflush => percentage ของ dirty page ใน buffer cache ที่อนุญาตให้ bdflush ไม่ต้องทำงาน (lower ratio)

Out-of-memory (OOM) Killer

โดยทั่วไปแล้ว หากมีการร้องขอ memory ผ่าน malloc (รวมถึง kmalloc และ vmalloc) ก็มักจะสำเร็จเสมอ แม้ในระบบจะมี memory ไม่เพียงพอก็ตาม เนื่องจาก linux kernel มองว่า คนที่ขอใช้ memory มักจะไม่ค่อยมีการใช้งานจริง ดังนั้นการ allocate memory จริงจะดำเนินการเมื่อมี request access เข้ามาจริงๆ เท่านั้น ถ้าระบบมี memory ไม่เพียงพอ มันก็จะรัน OOM Killer เพื่อพยายาม free memory ให้ได้ตามที่เราร้องขอ อย่างไรก็ตามวิธีการคืน memory ของ OOM นั้น มักจะไม่ค่อยเป็นมิตรเท่าไหร่ มันจะ kill process ที่มันมองว่า low priority ทิ้งไป

วิธีการทำงานดังกล่าว สร้างปัญหาให้กับ application พอสมควร โชคดีที่เราสามารถควบคุมการทำงานส่วนนี้ได้ผ่าน over commit policy (sysctl: vm.overcommit_memory)

  • 0 =>  เป็นค่า default
    • ถ้ามี memory เหลือก็จะอนุญาตให้ใช้งานได้
    • ถ้ามี memory ไม่พอ ก็จะไม่อนุญาตและ return error ให้ application กลับไป
  • 1 => อนุญาติให้ทำ overcommit ได้ เหมาะกับ scientific application ที่มักจะใช้ memory เยอะ
  • 2 => ไม่อนุญาติให้ทำ overcommit (address space = Swap + (50% of RAM)) ซึ่ง process จะไม่ถูก kill แต่จะพบ error memory allocation fail บางครั้ง
    • ค่า 50% สามารถแก้ไขได้ผ่าน vm.overcommit_ratio

References

Incoming search terms:

  • จัดการ virtual memory
  • oom killer คือ
  • base memory คือ
  • buffer memory คือ
  • https://yandex ru/clck/jsredir?from=yandex ru;search;web;;&text=&etext=1829 RClDSP8lJdsES3Rx321wfnhE-Xljtq0ON3jPq8AkR8U2TQQp_J05-CcFFcZ_u2cS da9ba65e86b8fa8ded6dc25b686bb64a97a5b279&uuid=&state=_BLhILn4SxNIvvL0W45KSic66uCIg23qh8iRG98qeIXme
  • kernel memory คืออะไร
  • linux ramคือ
  • lower oom value คืออะไร
  • OOM KILL คือ
  • overcommit ratio คือ
The following two tabs change content below.
Error: Unable to create directory wp-content/uploads/2018/11. Is its parent directory writable by the server?

Phuwadon Danrahan

An IT Technical Labour
Error: Unable to create directory wp-content/uploads/2018/11. Is its parent directory writable by the server?

Latest posts by Phuwadon Danrahan (see all)

Facebook Iconfacebook like buttonTwitter Icontwitter follow button
Copy Protected by Chetan's WP-Copyprotect.