810 likes | 1.15k Views
บทที่ 9 การจัดการหน่วยความจำ ( Virtual Memory Management ). หน่วยความจำเสมือน (Virtual Memory). หลักการจัดการหน่วยความจำหลักก็เพื่อให้สามารถนำโปรเซสลงหน่วยความจำให้ได้มากที่สุด (ทำให้ระบบมัลติโปรแกรมมิ่งทำงานย่างมีประสิทธิภาพมากที่สุด)
E N D
บทที่ 9การจัดการหน่วยความจำ(Virtual Memory Management)
หน่วยความจำเสมือน (Virtual Memory) • หลักการจัดการหน่วยความจำหลักก็เพื่อให้สามารถนำโปรเซสลงหน่วยความจำให้ได้มากที่สุด (ทำให้ระบบมัลติโปรแกรมมิ่งทำงานย่างมีประสิทธิภาพมากที่สุด) • หน่วยความจำเสมือน เป็นวิธีการหนึ่งที่สามารถทำให้โปรเซสทำงานได้ ถึงแม้ว่าโปรเซสนั้นจะไม่ได้อยู่ในหน่วยความจำหลักทั้งหมดก็ตาม โดยระบบปฏิบัติการจะทำหน้าที่เก็บบางส่วนของโปรแกรมที่กำลังทำงานไว้ในหน่วยความจำหลัก และเก็บที่ส่วนที่เหลือไว้ในฮาร์ดดิสก์ • ข้อดีหลักของวิธีนี้ ก็คือ โปรแกรมของผู้ใช้สามารถมีขนาดใหญ่กว่าหน่วยความจำจริงก็ได้ เพราะวิธีนี้จะสร้างหน่วยความจำทางตรรก ให้ดูเสมือนว่ามีหน่วยความจำเป็นแถวขนาดใหญ่
การแบ่งเป็นหน้า (Paging) • ระบบที่ใช้หน่วยความจำเสมือนส่วนใหญ่จะใช้เทคนิคที่เราเรียกว่า การแบ่งเป็นหน้า หรือ เพจจิ่ง(paging) • หลักการทำงาน • เป็นการแบ่งหน่วยความจำหลักออกเป็นพาร์ติชั่นที่มีขนาดเล็กและเท่ากัน • เราเรียกว่า เฟรม (frames) หรือ เพจเฟรม (page frame) • การแบ่งโปรแกรมในดิสก์ที่จะเข้ามาใช้งานเป็นชิ้นเล็ก ๆ เช่นกันเรียกว่า หน้า (page) โดยที่ทุกหน้าจะมีขนาดเท่ากันหมด และมีเงื่อนไขว่า • ขนาดของ 1 หน้า จะต้องเท่ากับขนาดของ 1 เพจเฟรม เสมอ • ใน 1 เฟรม จะมีการนำเอาแค่ 1 หน้า มาใส่ได้เท่านั้น เช่น หน่วยความจำหลัก 1 MB และแบ่งออกเป็น 4 เพจเฟรม ดังนั้น ขนาดของเพจเฟรมคือ 256 KB และ หน้าในดิสก์เท่ากับ 256 KB เหมือนกัน
การแบ่งเป็นหน้า (Paging) • โหลดโปรเซส A, B และ C ลงหน่วยความจำได้อย่างต่อเนื่อง จนกระทั่งนำโปรเซส B ออกไป แล้วทำการโหลดโปรเซส D ลงหน่วยความจำ ซึ่งสามารถทำได้โดยใช้แนวความคิดของแอ็ดเดรสทางตรรก (logical address) • โดยให้ระบบปฏิบัติการควบคุมการทำงานของโปรแกรมหรือโปรเซสในรูปแบบของตารางหน้า (page table)
การแบ่งเป็นหน้า (Paging) • การแบ่งเป็นหน้าแบบง่าย ๆ นั้นจะเหมือนกับการแบ่งพาร์ติชั่นแบบมีขนาดคงที่ ข้อแตกต่างอยู่ที่ว่าการแบ่งเป็นหน้านั้นจะเป็นการแบ่งพื้นที่ที่มีขนาดเล็ก และโปรแกรมหนึ่ง ๆ สามารถใช้งานได้มากกว่า 1 พาร์ติชั่นได้ และพาร์ติชั่นเหล่านี้ก็ไม่จำเป็นต้องต่อเนื่องกัน • วิธีการที่ทำให้การจัดการแบบแบ่งเป็นหน้าสามารถทำได้ง่ายขึ้นโดย เริ่มจากการแบ่งขนาดของเฟรม และขนาดของหน้าให้เป็นค่ายกกำลังของเลขฐาน 2 ซึ่งวิธีนี้แอ็ดเดรสทางตรรกจะแสดงเป็นเลขที่หน้า และระยะจากขอบหน้า (offset)
การแบ่งเป็นหน้า (Paging) • การกำหนดขนาดของหน้าเป็นค่าของเลขยกกำลัง 2 ทำให้ • โปรแกรมเมอร์ไม่จำเป็นต้องสนใจแอ็ดเดรสทางตรรกเลย เพราะว่าแอ็ดเดรสทางตรรกของโปรแกรมนั้นมีค่าเท่ากับแอ็ดเดรสเปรียบเทียบอยู่แล้ว (logical address=relative address) • การทำงานของฮาร์ดแวร์ในการแปลงที่อยู่นั้นจะทำได้ง่ายขึ้น เพราะว่าที่อยู่จะถูกเขียนอยู่ในรูปของ n + m บิต โดยบิตทางด้านซ้ายมือสุดจำนวน n บิต เป็นเลขที่หน้า และ บิตทางด้านขวามือจำนวน m บิตเป็นระยะจากขอบหน้า ในตัวอย่างก่อนหน้านี้ n=6 และ m=10 โดยการแปลงแอ็ดเดรส
การแบ่งเป็นหน้า (Paging) • การแปลงแอ็ดเดรสทำได้โดย • แยกเลขที่หน้าโดยนำบิตทางด้านซ้ายมือจำนวน n บิต ออกมาจากที่อยู่ทางตรรก • ใช้เลขที่หน้าเป็นตัวตั้งในตารางหน้าของโปรแกรม เพื่อนำไปใช้ค้นหาเลขที่เฟรม k ต่อไป • ที่อยู่ทางกายภาพของเฟรมนั้นคือ k x 2m และที่อยู่ทางกายภาพของหน่วยความจำหลักที่เทียบ ก็คือตัวเลขที่ได้บวกกับระยะจากขอบหน้า (เราไม่จำเป็นต้องคำนวณแอ็ดเดรสทางกายภาพอีกเพราะเราสามารถรวมเลขที่เฟรมกับระยะจากขอบหน้าได้เลย)
ตารางหน้า (page table) • ตารางหน้า (page table) นั้นเป็นการแมพค่าของแอ็ดเดรสทางตรรกไปหาค่าเลขที่เฟรมที่อยู่ในหน่วยความหลัก • ทางคณิตศาสตร์ อาจจะกล่าวได้ว่าตารางหน้านี้เป็นฟังก์ชั่นที่รับค่าของแอ็ดเดรสทางตรรกเป็นอินพุต (input) และให้ค่าแอ็ดเดรสทางกายภาพออกมา (output) ซึ่งสิ่งที่ฟังก์ชั่นดังกล่าวทำก็คือ แทนแอ็ดเดรสของเพจที่เป็นแอ็ดเดรสทางตรรกด้วยแอ็ดเดรสของเฟรม แต่ถึงแม้นการอธิบายข้างต้นจะดูเหมือนง่ายแต่ปัญหาที่พบมีอยู่ 2 หัวข้อคือ • ตารางหน้าส่วนใหญ่จะมีขนาดใหญ่ • การแมปค่าแอ็ดเดรสดังกล่าวจะต้องทำด้วยความเร็วสูง
ตารางหน้า (page table) • ตารางหน้าส่วนใหญ่จะมีขนาดใหญ่ • ในระบบคอมพิวเตอร์ปัจจุบันจะใช้ที่อยู่อย่างต่ำประมาณ 32 บิต ถ้าเรากำหนดให้แต่ละหน้ามีขนาด 4 KB ก็จะทำให้ระบบมีหน้าทั้งหมด 1 ล้านหน้า • ในระบบที่เป็นแบบ 64 บิต ก็จะทำให้มีจำนวนหน้ามากประมาณเกินกว่าที่จะนำไปใช้หมด (1012 หน้า) • การแมปค่าแอ็ดเดรสดังกล่าวจะต้องทำด้วยความเร็วสูง • การแมประหว่างแอ็ดเดรสทางตรรกและแอ็ดเดรสทางกายภาพนั้นจะต้องทำทุก ๆ ครั้งเมื่อมีการอ้างถึงแอ็ดเดรสจริงในหน่วยความจำหลัก • ใน 1 คำสั่งโปรแกรมอาจจะแมปเป็นจำนวน 1,2 หรือมากกว่านั้น และถ้ากำหนดให้แต่ละคำสั่งใช้เวลา 4 nsec ตารางหน้านั้นจะต้องมีความสามารถในการสืบค้นได้เร็วมากกว่า 1 nsec เพื่อป้องกันปัญหาคอขวด (bottleneck)
ตารางหน้า (page table) • ตารางหน้าประกอบไปด้วยอาร์เรย์ของรีจิสเตอร์ • เมื่อมีโปรเซสหนึ่งเริ่มทำงาน ระบบปฏิบัติการจะทำการโหลดรีจิสเตอร์ด้วยตารางหน้าของโปรเซสนั้น ๆ โดยทำการก็อบปี้จากหน่วยความจำหลัก ก็จะทำให้เราไม่ต้องอ้างถึงหน่วยความจำอีกในขณะที่โปรเซสกำลังทำงาน • ข้อดีของวิธีนี้ก็คือ เป็นวิธีที่ง่ายและไม่ต้องทำการอ้างถึงหน่วยความจำอีกเมื่อทำการแมปแอ็ดเดรส • ข้อเสียก็คือถ้าตารางของหน้ามีขนาดใหญ่ก็จะทำให้ระบบมีประสิทธิภาพในการทำงานต่ำลง เพราะการโหลดตารางหน้าทั้งหมดนั้นจะใช้เวลานาน
4 M บน 4 - 8 M ตารางลำดับแรก 0 - 4 M
ตารางหน้า (page table) • โครงสร้างตารางหน้า • Page frame number เป็นฟิลด์ที่มีความสำคัญมากที่สุดเพราะฟิลด์นี้ใช้ในการเก็บข้อมูลว่า หน้านี้จะไปอยู่ในเฟรมเลขที่อะไรในหน่วยความจำหลัก • Present/absent มีขนาด 1 บิต ใช้บอกว่าหน้านี้ในปัจจุบันอยู่ (present) หรือ ไม่อยู่ (absent) ในหน่วยความจำหลัก (1=อยู่, 0=ไม่อยู่) ถ้าเป็นเป็น 0 แล้ว จะทำให้เกิดปัญหาการผิดหน้าได้ (page fault)
ตารางหน้า (page table) • Protection เป็นบิตที่เก็บข้อมูลเกี่ยวกับการป้องกันหน้าว่าหน้านี้มีการป้องกันในการเรียกใช้งานอย่างไร เช่น ให้อ่านได้อย่างเดียว (Read Only), อ่านและเขียนได้ (Read/Write) หรือเอ็กซิคิวต์ได้ (Execute) ซึ่งการป้องกันนี้ใช้ 3 บิตก็พอ เช่น R (read), W (write), E (excute) เป็น 000,001,010,011}… เป็นต้น • Modified ใช้ในการเก็บข้อมูลเกี่ยวกับการใช้งานของหน้านั้น ว่าหน้าที่เข้าไปอยู่ในหน่วยความจำหลัก และที่ถูกใช้งานแล้ว หน้านั้นถูกบันทึกหรือปรับเปลี่ยนค่าหรือไม่ (0=ไม่มีการถูกบันทึกหรือปรับปรุงเปลี่ยนค่า, 1=มีการถูกบันทึกหรือปรับปรุงเปลี่ยนแปลงค่า) บิตนี้รู้จักกันในอีกชื่อหนึ่งว่า เดอร์ตี้บิต (dirty bit) เพราะเป็นบิตที่ระบบปฏิบัติการใช้ในการตรวจสอบสถานะของหน้า (ถ้าหน้าไหนเปลี่ยนแปลงจะเป็นบอตสกปรกที่ต้องถูกเขียนกลับลงดิสก์
ตารางหน้า (page table) • Referenced หน้าที่เข้าไปอยู่ในหน่วยความจำหลักนี้ ถูกเรียกใช้บ้างหรือไม่ (0=หน้านั้นยังไม่ถูกเรียกใช้งานตั้งแต่ถูกโหลดเข้าในหน่วยความจำหลัก, 1=หน้าที่ถูกเรียกใช้งานแล้ว) และบิตนี้จะเป็นบิตที่สำคัญสำหรับกระบวนการสับเปลี่ยนหน้า (page replacement) ที่เราจะเรียนรู้ในหัวข้อต่อไป • Caching disabled เป็นบิตที่ใช้กำหนดว่าเราไม่ต้องการเก็บค่าแคชสำหรับหน้านั้น โดยทั่วไปบิตนี้จะสำคัญสำหรับหน้าที่ถูกแมปเข้ากับริจิสเตอร์ของอุปกรณ์ เช่นในกรณีที่ระบบปฏิบัติการจะต้องรออุปกรณ์ภายนอกตอบสนองคำสั่งอยู่ตลอดเวลา
ตารางหน้า (page table) • เนื่องจากขนาดตารางหน้านั้นขึ้นอยู่กับจำนวนหน้าที่มี กล่าวคือ 1 แถวของตารางจะเท่ากับ 1 หน้าของโปรเซส • ถ้าโปรเซสมีขนาดใหญ่มาก ๆ ตารางหน้าก็จะมีขนาดใหญ่ไปด้วยซึ่งจะทำให้การทำงานในการแมปที่อยู่นั้นช้าลง • วิธีการแก้ก็คือ การทำตารางหน้าย้อนกลับ (inverted page table) โดยในระบบคอมพิวเตอร์หนึ่ง ๆ จะมีตารางหน้าย้อนกลับ ได้แค่ 1 ตาราง เท่านั้น เพราะแต่ละแถวในตารางหน้าย้อนกลับนั้น จะเป็นตัวแทนของ 1 เฟรม ในหน่วยความจำหลัก
ตารางหน้า (page table) • เช่น ในระบบที่ใช้ที่อยู่แบบ 64 บิต โดยแต่ละหน้ามีขนาด 4 KB (212) และมีขนาดของหน่วยความจำหลักเท่ากับ 256 MB (228) ซึ่งทำให้ตารางนี้มีทั้งหมด 65,536 แถว (2 28-12 = 216 = 65536) โดยในแต่ละแถวจะทำหน้าที่เก็บข้อมูลของ โปรเซส และเลขที่หน้าที่ใช้งานอยู่ในเฟรมในหน่วยความจำหลัก
ตารางหน้า (page table) • Process id เป็นหมายเลขโปรเซสที่อยู่ในเฟรมนั้น • Flag Bit จะแสดงถึงสถานะของโปรเซสที่อยู่ในเฟรม ซึ่งมี Referenced Bit, Modified Bit และ Present/Absent Bit อย่างในตารางหน้า • Page No จะแสดงหมายเลขหน้าของโปรเซสนั้นที่เข้ามาอยู่ในเฟรมนี้ • Counter จะเก็บค่าทุกครั้งที่โปรเซสเซอร์ หรือซีพียูทำการเรียกใช้ และอาจทำการบันทึกว่าถูกเรียกใช้งานครั้งสุดท้ายเมื่อไหร่ด้วย
ตารางหน้า (page table) • ตารางหน้าแบบย้อนกลับนี้จะช่วยให้เราประหยัดพื้นที่ได้ เมื่อแอ็ดเดรสหน่วยความจำเสมือนนั้นมีจำนวนมากกว่า แอ็ดเดรสในหน่วยความจำหลัก • วิธีดังกล่าวมีข้อเสียคือ การแปลงแอ็ดเดรสเสมือนไปหาแอ็ดเดรสจริงทางกายภาพนั้นทำได้ยากขึ้น • เมื่อมี โปรเซส n อ้างถึง หน้า p ฮาร์ดแวร์จะไม่สามารถทำการค้นหาแอ็ดเดรสจริง โดยการใช้ p เทียบเป็นอินเด็กซ์ของตารางได้อีกต่อไป • ตรงกันข้ามวิธีการค้นหาจะต้องทำการสืบค้นทุกแถวในตารางหน้าย้อนกลับ ซึ่งการค้นหาทุกแถวในตารางขนาด 64 K นั้นทำให้การทำงานช้าลงพอสมควร • วิธีแก้ปัญหาทำได้โดยใช้วิธี TLBs (Translation Lookaside Buffers) ถ้า TLB สามารถเก็บหน้าที่ถูกใช้งานบ่อย ๆ การแปลที่อยู่ก็สามารถทำได้เร็วเหมือนกับที่เราทำในตารางหน้าธรรมดา
ตารางหน้า (page table) • การใช้ตารางแบบย้อนกลับนี้จำเป็นต้องใช้ซอฟต์แวร์ช่วยในการสืบค้น ซึ่งคือการใช้ตารางแฮช และ ฟังก์ชั่นแฮช (hash function เป็นฟังก์ชั่นที่ใช้ในการแปลงข้อมูลที่มีความยาวมาก เป็นบิตที่มีจำนวนน้อยลงและค่าแฮชของข้อมูลแต่ละค่าไม่ควรมีค่าเหมือนกัน) • ในการแปลงที่อยู่เสมือน ดังรูปและหน้าที่อยู่ในหน่วยความจำที่มีค่าแฮชเหมือนกันก็จะมีการเชื่อมต่อเข้าหากัน (chained)
บัพเฟอร์ค้นหาที่อยู่ (Translation Lookaside Buffer) • โดยทั่วไป เมื่อมีการอ้างถึงหน่วยความจำเสมือนทุก ๆ ครั้ง จะมีการเรียกหาหน่วยความจำหลักถึง 2 ครั้ง คือมีการดึงแถวของตารางหน้า และการดึงข้อมูลที่ต้องการออกมาจากหน่วยความจำหลัก • การทำงานของหน่วยความจำเสมือนใช้เวลาในการเข้าถึงหน่วยความจำเป็น 2 เท่า • วิธีการป้องกันปัญหาดังกล่าวสามารถทำได้โดยใช้แคชหรือหน่วยความจำพิเศษในการเก็บแถวของตารางหน้า ที่เราเรียกกันว่า บัพเฟอร์ค้นหาที่อยู่ (TLB) โดยแคชนี้จะทำหน้าที่เก็บแถวของตารางหน้าที่พึ่งใช้เรียกใช้งานเสร็จ
บัพเฟอร์ค้นหาที่อยู่ (Translation Lookaside Buffer) • เมื่อมีการให้ค่าแอ็ดเดรสเสมือนกับระบบ โปรเซสเซอร์จะทำการสืบค้นในตาราง TLB ก่อน • ถ้าพบแถวที่ต้องการในตารางหน้า (TLB hit) เราก็สามารถเก็บเลขที่เฟรมและแปลงเป็นแอ็ดเดรสจริงได้เลย • แต่ถ้าไม่พบแถวที่ต้องการ (TLB miss) โปรเซสเซอร์ หรือซีพียูก็จะต้องใช้เลขที่หน้าไปเปรียบเทียบกับอินเด็กซ์ของตารางหน้า เพื่อหาแถวที่ต้องการ และซีพียูก็จะทำหน้าที่เพิ่ม TLB ให้มีแถวของตารางหน้าใหม่นี้ด้วย
บัพเฟอร์ค้นหาที่อยู่ (Translation Lookaside Buffer) • เนื่องจาก TLB จะเก็บข้อมูลของบางแถวจากตารางหน้าเท่านั้น ทำให้เราไม่สามารถเรียงลำดับแถวของ TLB ด้วยเลขที่หน้าได้ ดังนั้น ค่าของฟิลด์ในแถวของ TLB จะต้องมีเลขที่หน้ากำกับด้วย • การค้นหาเลขที่หน้าใน TLB ของโปรเซสเซอร์นั้นจะเป็นแบบการแมพร่วม(associative mapping) ซึ่งแตกต่างจากการแมพโดยตรงอย่างกันที่ทำในตารางหน้า • การออกแบบ TLB จะต้องพิจารณาถึงวิธีการจัดการกับค่าของแถวที่อยู่ในตาราง และวิธีการแทนที่ค่าของแถวใหม่เข้าไปในตาราง
การสับเปลี่ยนหน้า (Page replacement algorithms) • การเลือกหน้าในหน่วยความจำที่จะถูกแทนที่ด้วยหน้าใหม่ที่เข้ามา • คำถามที่น่าสนใจในการสับเปลี่ยนหน้า • มีจำนวนเพจเฟรมเท่าไหร่ที่สามารถให้กับโปรเซสแต่ละตัวได้ • กลุ่มของหน้าถูกพิจารณาให้สับเปลี่ยนหน้านั้นควรจะถูกจำกัดหรือไม่ เพื่อป้องกันไม่ให้โปรเซสที่ทำให้เกิดการผิดหน้า (page fault) ทำงาน • ในกลุ่มของหน้าที่เราพิจารณา เราจะเลือกหน้าใดที่จะนำไปสับเปลี่ยน
การสับเปลี่ยนหน้า (Page replacement algorithms) • หัวข้อที่ 1 และ 2 เกี่ยวข้องกับ การจัดการภายใน (Resident Set Management) ซึ่งเป็นการจัดการที่เกี่ยวข้องกับนโยบายที่เราสามารถกำหนดเองได้ เพื่อให้ระบบปฏิบัติการสามารถตัดสินใจว่า “ต้องการนำหน้าของโปรเซสเข้ามาเท่าไหร่ในหน่วยความจำ” หรือว่า “ต้องการให้หน่วยความจำหลักกับโปรเซสบางตัวเป็นจำนวนเท่าไหร่” ลองพิจารณา • ถ้าขนาดหน้าของหน่วยความจำน้อย จะทำให้มีจำนวนโปรเซสเข้ามาใช้งานหน่วยความจำมากขึ้น ทำให้ความน่าจะเป็นของระบบปฏิบัติการสามารถค้นพบโปรเซสอย่างน้อยหนึ่งโปรเซสที่พร้อมที่จะทำงานมากขึ้น และทำให้เสียเวลาในการสลับหน้าน้อยลง
การสับเปลี่ยนหน้า (Page replacement algorithms) • ถ้าจำนวนหน้าของโปรเซสหนึ่ง ๆ ที่สามารถอยู่ในหน่วยความจำหลักน้อย (จำนวนเฟรมน้อย) จะทำให้อัตราการเกิดการผิดหน้าสูงมากขึ้น เพราะว่าความสัมพันธ์ระหว่างอัตราการผิดหน้าและจำนวนเฟรมในหน่วยความจำเป็นแบบไฮเพอร์บอลา (hyperbola) ดังในรูป • ถ้าการกำหนดขนาดของหน้าคงที่แล้ว การให้หน่วยความจำเพิ่มกับโปรเซสใดโปรเซสหนึ่งจะไม่มีผลกระทบต่ออัตราการผิดหน้ามากนัก • หัวข้อที่ 3 เกี่ยวข้องกับวิธีใช้และอัลกอริทึ่มของการสับเปลี่ยนหน้าซึ่งเราจะพิจารณารายละเอียดต่อไป
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • วิธีสับเปลี่ยนแบบมาก่อน-ออกก่อน (First-in First-out Algorithm) • ใช้เวลาที่หน้านั้นถูกนำเข้ามาในหน่วยความจำเป็นเกณฑ์ในการตัดสินใจ • เมื่อต้องการเลือกหน้าบางหน้าออก ก็ให้เลือกจากหน้าที่เข้ามานานที่สุด • เราอาจจะไม่ต้องจดเวลาจริง ๆ ที่หน้านั้นเข้ามาใช้งานก็ได้ เพียงแต่สร้างคิวแบบมาก่อน-ออกก่อน (FIFO queue)
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • วิธีสับเปลี่ยนแบบมาก่อน-ออกก่อน (First-in First-out Algorithm) • จากตัวอย่าง เกิดการผิดหน้า 15 ครั้ง • การผิดหน้าก็จะเกิดขึ้นเกือบจะทันทีเมื่อนำหน้าที่กำลังใช้งานนั้นกลับมา และหน้าบางหน้าในหน่วยความจำก็จะถูกสับเปลี่ยนออกไปแทน • การสับเปลี่ยนที่ไม่ดีจะเพิ่มอัตราการผิดหน้าได้ และทำให้การทำงานของโปรเซสช้าลง แต่จะไม่ทำให้ระบบทำงานผิดพลาด • ปกติกำหนดเฟรมที่มียิ่งมากจะทำให้เกิดการผิดหน้าน้อยลง แต่ปรากฏณ์นี้ไม่จริงเสมอไป จากตัวอย่างที่จะกล่าวต่อไป จะเห็นว่าเมื่อมีจำนวนเฟรมเป็น 4 จะเกิดการผิดหน้าน้อยกว่าเมื่อมีจำนวนเฟรมเป็น 3 ลักษณะที่เกิดนี้เรียกว่า ปรากฎการณ์เบลาดี้ (Balady’s anomaly)
Reference string : 1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5 กราฟการผิดหน้าของวิธีสับเปลี่ยนแบบมาก่อน-ออกก่อน
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • วิธีสับเปลี่ยนแบบให้โอกาสครั้งที่สอง (Second Chance Page Replacement Algorithm) • ปรับปรุงวิธี FIFO โดยการป้องกันการเปลี่ยนหน้าที่ถูกเรียกใช้งานบ่อยออกไป • ทำได้โดยการเช็คที่บิต Referenced (R) ของหน้าที่เข้ามานานที่สุด • ถ้าบิต R มีค่าเป็น 0 ก็แสดงว่าหน้านั้นเก่าและไม่ได้ถูกเรียกใช้งานเลย ระบบก็สามารถทำการสับเปลี่ยนได้ทันที • ถ้าบิต R มีค่าเท่ากับ 1 ก็ให้กำหนดให้บิต R นั้นเป็น 0 และนำหน้านั้นกลับไปเข้าแถวใหม่อีกครั้ง • ทำการเปลี่ยนแปลงเวลาของหน้านั้นใหม่เหมือนดังหน้านั้นพึ่งเข้ามาในหน่วยความจำ จากนั้นก็ทำการค้นหาหน้าที่จะถูกสับเปลี่ยนต่อไป
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • วิธีการสับเปลี่ยนแบบวงรอบนาฬิกา (Clock Page Replacement Algorithm) • วิธีการให้โอกาสครั้งที่สองจะเป็นวิธีการที่เป็นเหตุเป็นผลพอสมควร แต่ไม่มีประสิทธิภาพมากนัก • เพราะการที่ระบบย้ายหน้าไปมาในลิสต์นั่นทำให้ระบบเสียเวลาพอสมควร • วิธีการที่สามารถปรับปรุงวิธีการดังกล่าวได้ก็คือ ให้เราเรียงเฟรมทุกเฟรมเป็นรูปวงกลมให้เหมือนรูปนาฬิกา และมีเข็มนาฬิกาชี้ไปที่หน้าที่เก่าที่สุด
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • วิธีการสับเปลี่ยนแบบวงรอบนาฬิกา (Clock Page Replacement Algorithm) • เมื่อมีการผิดหน้าเกิดขึ้น หน้าที่มีเข็มนาฬิกาชี้อยู่จะถูกตรวจสอบ • ถ้าบิต R มีค่าเป็น 0 หน้านั้นก็จะถูกสับเปลี่ยนออกไป และหน้าใหม่ก็จะถูกใส่เข้ามาในตำแหม่งเดิม พร้อมกันนั้น เข็มนาฬิกาก็จะทำการเลื่อนไปด้านหน้า 1 ตำแหน่ง • แต่ถ้าบิต R ถูกกำหนดเป็น 1 ก็ให้ลบค่าของบิตนั้นเป็น 0 และเลื่อนเข็มไปหน้าถัดไป • วิธีดังกล่าวจะถูกทำซ้ำจนกว่าเราจะได้หน้าที่มีบิต R เป็น 0 ซึ่งวิธีการนี้จะเหมือนวิธีการแบบให้โอกาสครั้งที่ 2 เลย เพียงแต่แตกต่างกันไปในวิธีการใช้งานเท่านั้น
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • วิธีสับเปลี่ยนแบบที่ดีที่สุด(Optimal Page Replacement Algorithm) • วิธีสับเปลี่ยนหน้าที่ดีที่สุด ที่จะทำให้อัตราการผิดหน้าต่ำที่สุด • จะต้องไม่เกิดปรากฏการณ์เบลาดี้ • วิธีการก็คือ “ให้เลือกสับเปลี่ยนหน้าที่จะไม่ถูกเรียกใช้งาน และมีระยะเวลารอการเรียกใช้ที่นานที่สุด”
วิธีนี้จะทำให้เกิดการผิดหน้า 9 ครั้ง ซึ่งดีกว่าวิธีแบบ FIFOมาก (มีการผิดหน้า 15 ครั้ง) • ถ้าไม่คิดการผิดหน้า 3 ครั้งแรก ซึ่งจะต้องเกิดขึ้นอย่างแน่นอน จะเห็นได้ว่าแบบที่ดีที่สุดนี้ดีกว่าแบบ FIFO ได้ถึง 2 เท่า • วิธีแบบที่ดีที่สุดนี้ยากที่จะสร้างได้จริง ๆ เพราะเราต้องรู้ในอนาคตว่า จะมีการเรียกหน้าใดเมื่อไหร่ • วิธีแบบที่ดีที่สุดนี้ จึงมีไว้เพื่อใช้ในการเปรียบเทียบเท่านั้น
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • การสับเปลี่ยนแบบที่ไม่ได้ใช้งาน-ออกก่อน (NRU : Not Recently Used) • นำวิธีการสับเปลี่ยนแบบวงรอบนาฬิกามาเพิ่มประสิทธิภาพ • โดยพิจารณาบิตสำคัญในตารางหน้าเพิ่มขึ้นอีกหนึ่งบิต ซึ่งก็คือวิธีแบบที่ไม่ได้ใช้งาน-ออกก่อน (NRU) • เนื่องจากระบบปฏิบัติการสามารถทำการเก็บข้อมูลสถิติว่าหน้าใดที่กำลังถูกใช้ หรือ ที่ไม่ได้ใช้งาน ได้จากบิตในแถวของตารางหน้าที่แสดงสถานะ การทำงานของแต่ละหน้า • บิต Referenced จะถูกกำหนดเป็น 1 เมื่อหน้านั้นถูกเรียกใช้งาน และบิต Modified จะถูกกำหนดเป็น 1 เมื่อหน้านั้นมีการเปลี่ยนแปลง
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • การสับเปลี่ยนแบบที่ไม่ได้ใช้งาน-ออกก่อน (NRU : Not Recently Used) • บิตทั้งสองนั้นเป็นฟิลด์ที่อยู่ในแถวของตารางหน้า และจะถูกเปลี่ยนแปลงค่าทุกครั้งเมื่อมีการเรียกใช้งาน • วิธีการสับเปลี่ยนหน้าแบบนี้เป็นดังนี้ • เริ่มทำงาน บิตทั้งสองในทุก ๆ หน้าจะถูกกำหนดเป็น 0 • เมื่อครบวงรอบของระยะเวลาหนึ่ง ๆ เช่น จากการแทรกของอินเทอร์รัพต์ (clock interrupt) บิต R ก็จะถูกกำหนดค่าเป็น 0 เพื่อเป็นตัวแยกหน้าที่ไม่ได้ถูกเรียกใช้งานออกจากหน้าอื่น ๆ • เมื่อมีการผิดหน้าเกิดขึ้น ระบบปฏิบัติการจะทำการตรวจสอบทุกหน้าและแบ่งหน้าเหล่านั้นออกเป็น 4 กลุ่ม ขึ้นอยู่กับค่าของบิต R และ บิต M
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • การสับเปลี่ยนแบบที่ไม่ได้ใช้งาน-ออกก่อน (NRU : Not Recently Used) • กลุ่มที่ 0: ไม่ถูกเรียกใช้งาน และ ไม่มีการเปลี่ยนแปลงค่า • กลุ่มที่ 1: ไม่ถูกเรียกใช้งาน แต่ มีการเปลี่ยนแปลงค่า • กลุ่มที่ 2: ถูกเรียกใช้งาน แต่ ไม่มีการเปลี่ยนแปลงค่า • กลุ่มที่ 3: ถูกเรียกใช้งาน และ มีการเปลี่ยนแปลงค่า • ดูเหมือนว่า ไม่มีทางเป็นไปได้ที่จะมีหน้าอยู่ในกลุ่มที่ 1 แต่ มันก็อาจจะเกิดขึ้นได้ ในกรณีที่หน้าในกลุ่มที่ 3 นั้นถูกระบบปฏิบัติการทำการกำหนดบิต R เป็น 0 เมื่อครบวงรอบของระยะเวลาหนึ่ง ๆ ซึ่งระบบปฏิบัติการไม่ได้กำหนดบิต M เป็น 0 ด้วย เพราะเราต้องการข้อมูลที่ว่าหน้านั้นจะต้องถูกเขียนทับกลับลงไปในดิสก์ด้วยหรือไม่ จึงทำการเคลียร์บิต R แต่ ไม่แตะต้องบิต M และทำให้หน้านั้นอยู่ในกลุ่มที่ 1
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • การสับเปลี่ยนแบบที่ไม่ได้ใช้งาน-ออกก่อน (NRU : Not Recently Used) • วิธีนี้จะสุ่มเอาหน้าออกจากกลุ่มลำดับต่ำสุด (เช่นกลุ่มที่ 1 มีลำดับต่ำกว่ากลุ่มที่ 2 และ 3 ตามลำดับ) ที่มีหน้าของโปรเซสอยู่ • วิธีการนี้ยังดูเหมือนว่าจะพยายามที่จะนำเอาหน้าที่ถูกเปลี่ยนแปลงแต่ไม่ได้ถูกเรียกใช้งานหรืออ้างอิงถึงออกทุกครั้งที่มีการครบวงรอบนาฬิกา (ประมาณ 20 msec) มากกว่าหน้าที่ไม่มีการเปลี่ยนแปลงแต่ถูกเรียกใช้งานบ่อย • ข้อเด่นของวิธี NRU คือ ง่ายที่จะทำความเข้าใจ, ไม่ยากเกินไปที่จะนำมาใช้งานจริง และ มีประสิทธิภาพค่อนข้างดี
อัลกอริทึ่มการสับเปลี่ยนหน้าอัลกอริทึ่มการสับเปลี่ยนหน้า • การสับเปลี่ยนแบบใช้งานน้อยที่สุด-ออกก่อน (Least Recently Used) • วิธีแบบที่ดีที่สุด (OPT) เป็นไปไม่ได้ในทางปฏิบัติ • แบบ FIFO จะดูเวลาที่สับเปลี่ยนหน้าเข้ามาในหน่วยความจำ • แบบ OPT จะดูเวลาที่หน้าถูกเรียกใช้งาน • ถ้าเราใช้ข้อมูลในอดีตที่ผ่านมา ประมาณการณ์อนาคตอันใกล้ เราอาจจะสับเปลี่ยนหน้าที่ไม่ได้ถูกเรียกใช้งาน เป็นเวลานานที่สุด ซึ่งเรียกว่า แบบใช้งานน้อยที่สุด-ออกก่อน (LRU) • วิธีนี้จะบันทึกเวลาที่แต่ละหน้าถูกอ้างอิงครั้งล่าสุดไว้ เมื่อต้องการเลือกหน้า เพื่อสับเปลี่ยนออก ก็จะเลือกหน้าที่ไม่ได้ใช้มาเป็นเวลานานสุด (หน้าที่มีตัวเลขเวลาน้อยที่สุด) • จะเห็นได้ว่าวิธีการนี้ มองย้อนเวลาไปในอดีต แทนที่จะมองไปในอนาคต