OS จัดการกับ Main Memory ยังไงนะ? - Memory Partitioning
Published on
Authored by Pete. Pittawat Taveekitworachai.
แน่นอนว่าระบบคอมพิวเตอร์หนึ่ง ๆ ต้องการพื้นที่สำหรับวางข้อมูลไว้เพื่อนำไปใช้ได้อย่างรวดเร็ว และ Main Memory ก็คือสิ่งที่เรากำลังพูดถึงกันอยู่นั่นเอง อย่างไรก็ตาม เราทุกคนต่างรู้ดีว่า Main Memory นั้นมีพื้นที่ต่อราคาที่ค่อนข้างแพงเมื่อเทียบกับ Hard Disk Drive (HDD) (ยกเว้นว่าคุณจะมาจากโลกอนาคตที่เราหาวิธีทำให้มันถูกได้แล้ว หรือกลายเป็นของล้าสมัยไป: สวัสดีมนุษย์หรือหุ่นยนต์จากอนาคต! 👨🏻🤖)
ด้วยเหตุนี้เองระบบปฏิบัติการ (OS: Operating System) ก็ต้องพยายามทำอย่างไรก็ได้เพื่อให้การบริหารจัดการ Main Memory เป็นได้ด้วยความคุ้มค่ามากที่สุด ซึ่งก็มีหลากหลายวิธี แล้วแต่ผู้พัฒนาระบบปฏิบัตการแต่ละแห่งจะเลือกสรรวิธีที่ตนคิดว่าดีที่สุด และเนื่องจากระบบปฏิบัติการเป็นสิ่งที่ยังคงมีการพัฒนาอยู่เสมอ สังเกตได้จาก Windows Update หรือ macOS Update ที่มักจะมาตอนเรารีบ ๆ 😅 แน่นอนว่าทั้งฟีเจอร์ใหม่ ๆ ความปลอดภัยที่เพิ่มขึ้น รวมไปถึงประสิทธิภาพในการจัดการทรัพยากรของคอมพิวเตอร์เองก็มีการเปลี่ยนแปลงตลอดเวลา
ดังนั้นในบทความนี้จะมาพูดถึงวิธีการพื้นฐานมาก ๆ ที่ระบบปฏิบัติการยุตแรก ๆ เลือกใช้เพื่อให้เข้าใจถึงพื้นฐานการจัดการหน่วยความจำหลักในเบื้องต้น
🔑 Key terms
ก่อนจะไปพูดถึงหัวข้อหลักของเราวันนี้ ก็คงต้องขอกล่าวถึงนิยามของสิ่งที่จะพูดถึงในบทความนี้สักหน่อย เพื่อความเข้าใจที่ตรงกัน
- OS = ระบบปฏิบัติการ
- Process = โปรแกรมที่กำลังรันอยู่ (หมายเหตุ: ไม่ใช่นิยามที่เป็นทางการ สามารถอ่านเพิ่มเติมได้ที่ Process (computing))
- Main Memory = หน่วยความจำหลัก เช่น RAM
Memory Partitioning
เนื่องจากแต่ละ Process ในระบบนั้นมีขนาดที่ไม่เท่ากัน บาง Process มีขนาดเล็ก ไม่ต้องการพื้นที่มากในหน่วยความจำ บาง Process มีขนาดใหญ่ต้องการพื้นที่ในหน่วยความจำมาก ดังนั้นในยุคแรก ๆ ของระบบปฏิบัติการจึงเกิดไอเดียของการ Parition หรือการแบ่งพื้นที่ทั้งหมดในหน่วยความจำออกเป็นส่วนย่อย ๆ ขึ้นมา ซึ่งแต่ละ Process ก็จะถือครองพื้นที่หนึ่งส่วนนั้น ๆ ไว้ Memory Partitioning นั้น แบ่งออกได้เป็น 2 แบบหลัก ๆ ด้วยกัน คือ
- Fixed Partitioning มีการแบ่งพื้นที่ของ Main Memory ตั้งแรกเริ่มต้นระบบปฏิบัติการ เช่น การเปิดเครื่อง และจะคงแบบนั้นไปตลอด เช่น แบ่งออกเป็น 16 ช่อง ก็จะ 16 ช่องไปตลอด
- Dynamic Partitioning เมื่อเริ่มต้นระบบจะไม่มีการแบ่งพื้นที่ พื้นที่จะถูกแบ่งไปตามความต้องการระหว่างการใช้งาน โดยที่ช่องที่แบ่งอาจมีเพิ่มหรือลดได้ตามความจำเป็น
Fixed Partitioning
เมื่อมีการแบ่งช่องแล้ว (ซึ่งโดยทั่วไปจะเป็นตอนเริ่มต้นระบบปฏิบัติการ) จะคงอยู่แบบนั้นตลอดไป แบ่งออกได้เป็น 2 แบบ
- Equal-size Partitioning
การแบ่งหน่วยความจำหลักออกเป็นพื้นที่ขนาดเท่า ๆ กัน เช่น หากเรามีหน่วยความจำหลักขนาด 64MB เราสามารถแบ่งออกได้เป็น 8MB จำนวน 8 ช่องนั่นเอง (8x8MB = 64MB)
ข้อดีของวิธีนี้ คือ ง่ายสำหรับระบบปฏิบัติการ เนื่องจากไม่ต้องคิดอะไรมาก แค่แบ่งให้เท่า ๆ กันก็พอ อย่างไรก็ตามข้อเสียของวิธีนี้ก็คือ ถ้าสมมติว่าในหน่วยความจำหลักของเราตอนนี้มีหน้าตาแบบนี้
จะเห็นได้ว่าเราเหลือพื้นที่อยู่ 16MB แต่ถ้าหากมี Process ที่มีขนาด 12MB เข้ามา สิ่งที่เกิดขึ้น คือ Process นั้นจะไม่สามารถโหลดเข้ามาได้ เพราะอย่างที่เคยกล่าวไว้ หนึ่งช่องมี Process เป็นเจ้าของได้แค่หนึ่งอันเท่านั้น
ในทางตรงกันข้าม หากระบบของเราเต็มไปด้วย Process ขนาดเล็ก เช่น 2MB ถูกโหลดเข้ามา หนึ่งช่องในหน่วยความจำหลักซึ่งมีขนาด 8MB ตามที่เราแบ่งไว้ในตอนแรก จะถูกเป็นเจ้าของได้โดย Process เดียวเท่านั้น ทำให้เราเสียพื้นที่ไปโดยเปล่าประโยชน์ถึง 6MB ในช่องนั้น ๆ ที่ Process ขนาด 2MB ถูกโหลดเข้ามา
เราเรียกเหตุการณ์ที่ Process มีขนาดเล็กกว่าช่องจนทำให้เกิดการเสียพื้นที่ไปโดยเปล่าประโยชน์ว่า Internal Fragmentation
- Unequal-size Partitioning
เนื่องจากวิธีข้างต้นเราได้เห็นถึง 2 ปัญหาที่กล่าวไปแล้ว ก็ได้มีความพยายามในการลดปัญหาดังกล่าวลง โดยแทนที่เราจะแบ่งพื้นที่เท่า ๆ กันในทุกช่อง ก็แบ่งให้ไม่เท่ากันแทน เช่น เรามีหน่วยความจำหลักขนาด 64MB เราสามารถแบ่งออกได้เป็น 1MB + 1MB + 2MB + 4 MB + 8MB + 16MB + 32MB = 64MB ซึ่งจะเห็นได้ว่าวิธีนี้ Process ขนาดเล็กก็เข้าช่องเล็ก, Process ขนาดใหญ่ก็เข้าช่องที่มีขนาดใหญ่ขึ้น ทำให้ลดปัญหาของ Internal Fragmentation ลง นอกจากนี้ Process ที่มีขนาดใหญ่มากยังมีโอกาสมากขึ้นที่จะโหลดเข้ามาในหน่วยความจำหลัก แต่อย่างไรก็ตามข้อเสียก็ยังคงอยู่ ดังจะเห็นได้จากที่เรามีช่องใหญ่ (32MB) เพียงช่องเดียวเท่านั้น เพราะฉะนั้น Process ขนาดใหญ่ก็อาจจะต้องรอ Queue เพื่อที่จะใช้งานในช่องนั้น นอกจากนี้อาจเกิดเหตุการณ์ที่ Process ที่มีขนาดเล็กเข้าไปในช่องใหญ่ได้ด้วย ทำให้ปัญหาของ Internal Fragmentation ยังคงอยู่
ลองจินตนาการ ถึงเวลาที่ระบบเราไม่มี Process ขนาดใหญ่เลย มีแต่ Process ขนาด 1MB จำนวน 6 โดยที่ตอนนี้ช่องของ 1MB กำลังโดนใช้อยู่ เนื่องจากระบบปฏิบัติการต้องการทำให้ Utilization ของทรัพยากรระบบสูงที่สุด นั่นทำให้ช่องว่างทั้งหมดที่เหลือถูกจับจองโดย Process ขนาด 1MB ทั้งหมด จังหวะเดียวกันนั้นเอง Process ในช่อง 1MB ตอนแรกทำงานเสร็จพอดีจึงคืนช่องนั้นให้กับระบบ และก็มี Process ขนาด 32MB เข้ามาพอดี แม้ว่า ขณะนั้นเราจะรู้ว่าเรามี Free Space รวมถึง 58MB แต่มันก็กระจัดกระจายไปตามแต่ละช่องอยู่ดี Process ขนาด 32MB จึงไม่สามารถโหลดเข้ามาได้และต้องรอนั่นเอง
Dynamic Partitioning
เราได้เห็นถึงปัญหามากมายของการแบ่งช่องแบบเท่า ๆ กัน Dynamic Partitioning จึงเข้ามาเพื่อแก้ปัญหาข้างต้นไป เราเห็นกันไปแล้วว่า Fixed Partitioning มีปัญหาในแง่ของ Internal Fragmentation ทำให้เหลือพื้นที่เปล่าประโยชน์ ดังนั้น Dynamic Partitioning จึงแก้โดยการที่ให้ Process แต่ละอันเป็นคนบอกเองว่าต้องการพื้นที่เท่าไร และจองพื้นที่เท่าที่ใช้เท่านั้น ดังนั้นช่องแต่ละช่องก็จะไม่เท่ากัน และมีขนาดที่พอดีกับ Process แต่ละตัวนั่นเอง
อย่างไรก็ตามวิธีนี้ก็มีข้อเสียเช่นกัน นั่นก็คือสิ่งที่เรียกว่า External Fragmentation สิ่งหนึ่งที่ External Fragmentation แตกต่างจาก Internal Fragmentation ก็คือ Internal Fragmentation เป็นพื้นที่ที่สูญเปล่าไปภายในช่องที่ Process นั้น ๆ เป็นเจ้าของ แต่ External Fragmentation เป็นพื้นที่ที่สูญเปล่าไประหว่างช่องที่เป็นเจ้าของโดย Process สอง Process นั่นหมายความว่าพื้นที่ที่สูญเปล่าที่ถูกจัดเป็น External Fragmentation ไม่มี Process ใดเป็นเจ้าของนั่นเอง
ดังที่จะเห็นได้จากภาพว่าแม้ว่าพื้นที่ย่อย ๆ รวมกันจะมีพื้นที่เพียงพอสำหรับ Process ใหม่ที่มีขนาด 16MB แต่ Process นั้นกลับไม่สามารถถูกโหลดเข้ามาใน Main Memory ได้ เพราะปัญหา External Fragmentation นั่นเอง ซึ่งการเกิด External Fragmentation นั้น เกิดจาการที่ Process ที่เคยถือครองพื้นที่ของช่องนั้น ๆ ได้ทำงานจนเสร็จแล้วคืนพื้นที่ให้ระบบจึงเกิดเป็นพื้นที่ว่างขนาดเท่าที่ Process เคยถือไว้นั่นเอง
ความพยายามในการจัดการปัญหา External Fragmentation หลัก ๆ จะมีด้วยกัน 2 วิธี คือ Compaction และการใช้ Placement Algorithms ซึ่งในบทความนี้จะขอกล่าวเพียงวิธีแรกเท่านั้น สำหรับวิธีที่สองจะพบกันได้ในบทความถัดไป โดย Compaction นั้นจะเป็นวิธีที่แก้ปัญหาได้แต่มีข้อเสียบางอย่างที่ทำให้ทำได้ไม่บ่อยนัก ส่วน Placement Algorithms เป็นความพยายามที่จะลดปัญหา (ลดขนาด) ของ External Fragmentation ลง
Compaction ไปหนึ่งในวิธีที่จะกำจัดทุก External Fragmentation ให้หมดไปด้วยการ Compact บีบอัด Process ทุก Process ให้ไปอยู่ด้วยกันดังภาพ ผลลัพธ์ที่ได้คือพื้นที่วางขนาดใหญ่ ทำให้ Process ที่มีขนาดใหญ่สามารถโหลดเข้ามาได้อย่างง่ายดาย อย่างไรก็ตามวิธีนี้มีข้อเสียที่เห็นได้ชัด คือ การเสียเวลาที่ CPU จะต้องมาจัดการ Compaction ใน Main Memory แทนที่จะได้ไปรัน Process อื่น ๆ ทำให้ OS เองเลือกที่จะทำสิ่งนี้ไม่บ่อยนัก เนื่องจากเป็นการลด Throughput (จำนวน Process ที่ทำงานเสร็จในหนึ่งหน่วยเวลา) ของระบบลง
Final Thought
แน่นอนว่าวิธีเหล่านี้นั้น เราอาจจะไม่ได้เห็นระบบปฏิบัติการในปัจจุบันนำไปใช้กันตรง ๆ อีกแล้ว ด้วยวิวัฒนาการของระบบปฏิบัติการตามเวลา และด้วยทรัพยากรของระบบที่มีมากขึ้น แต่อย่างไรก็ตาม ผู้เขียนเชื่อว่าการศึกษาหลักการทำงานของระบบปฏิบัติการนั้นคงมีประโยชน์ไม่มากก็น้อย เนื่องด้วยระบบปฏิบัติการนั้นว่าด้วยการจัดการทรัพยากรต่าง ๆ เช่น พื้นที่, คนทำงาน, ช่องทางการติดต่อ รวมไปถึงเวลาด้วยเช่นกัน ดังนั้นเราอาจกล่าวได้ว่าการศึกษาระบบปฏิบัติการนั้นก็ช่วยให้เราเป็นนักจัดการได้ดียิ่งขึ้นนั่นเองทั้งในชีวิตการทำงาน และชีวิตปัจจุบัน