OS · บทที่ 7 Address Translation

หัวข้อ 17 · 22 นาที

Base & Bounds, Segmentation และ Paging

นึกภาพก่อน

โรงแรมทุกแห่งมีห้อง 101 แขกบอกแท็กซี่ว่า "ห้อง 101" ไม่ได้ ต้องบอกชื่อโรงแรมด้วย แต่ ภายใน โรงแรม ทุกคนพูดแค่เลขห้อง และไม่มีใครสับสนกับห้อง 101 ของโรงแรมอื่น

process ก็เหมือนกัน: ทุก process คิดว่า memory ของตัวเองเริ่มที่ address 0 (virtual address) hardware แปลงเป็นตำแหน่งจริงใน RAM (physical address) ทุกครั้งที่มีการอ้างถึง โดยที่ process ไม่รู้ตัว

text
processor ──virtual address──▶ translation ──valid──▶ physical address ──▶ physical memory
                                    │
                                    └──invalid──▶ raise exception

เป้าหมายของ address translation

  • Memory protection — process แตะ memory ของคนอื่นหรือของ kernel ไม่ได้
  • Memory sharing — เช่น shared library, interprocess communication
  • Sparse addresses — มีหลายบริเวณที่จองแบบ dynamic (heap, stack) กระจายใน address space ที่กว้าง
  • Efficiency — การวางใน memory, การ lookup ตอนรัน, ตารางที่กระทัดรัด

ของแถม: ถ้า kernel ดักได้ทุกครั้งที่โปรแกรมอ่านหรือเขียน virtual address ที่เลือกไว้ ก็ทำได้อีกหลายอย่าง: copy on write, fill on demand, demand paging (เทคนิคของ virtual memory), memory-mapped file

วิธีที่ 1: Base and Bounds

แต่ละ process มี register สองตัว:

  • base — ตำแหน่งเริ่มของ process ใน physical memory
  • bound — ขนาดของพื้นที่
text
ถ้า virtual address ≥ bound  →  raise exception
ไม่เช่นนั้น  physical address = base + virtual address
ข้อดีข้อเสีย
ง่ายกันโปรแกรมเขียนทับ code ของตัวเองไม่ได้ (ทั้งก้อนมีสิทธิ์เดียว)
เร็ว (register 2 ตัว, adder, comparator)share code/data กับ process อื่นไม่ได้
ปลอดภัยขยาย stack/heap ตามต้องการไม่ได้ (เป็นก้อนเดียวต่อเนื่อง)
ย้ายตำแหน่งใน physical memory ได้ โดยไม่ต้องแก้ process (แค่เปลี่ยน base)

วิธีที่ 2: Segmentation

แทนที่จะมี base/bound คู่เดียว ให้มี หลายคู่ คู่ละส่วนของโปรแกรม

  • Segment คือบริเวณต่อเนื่องของ virtual memory
  • แต่ละ process มี segment table (ใน hardware) — หนึ่งแถวต่อหนึ่ง segment
  • แต่ละ segment มี: start, length, access permission
  • segment อยู่ที่ใดใน physical memory ก็ได้
  • process share segment กันได้: start และ length เดียวกัน สิทธิ์เหมือนหรือต่างกันก็ได้

virtual address แบ่งเป็นสองส่วน: segment # กับ offset

text
1. แยก virtual address → segment #, offset
2. เปิด segment table แถวที่ segment #
3. ถ้า offset ≥ length → exception
4. ถ้าชนิดการเข้าถึงไม่ได้รับอนุญาต → exception
5. physical address = start + offset

ตัวอย่างจากสไลด์

address 14 bit: 2 bit บนเป็น segment # และ 12 bit ล่างเป็น offset (เลขฐานสิบหก 3 หลักพอดี)

segment #segmentstartlength
0code0x40000x700
1data00x500
2heap––
3stack0x20000x1000
virtualsegment #offsetตรวจphysical
0x0240 (main)0 (code)0x2400x240 น้อยกว่า 0x700 ✓0x4000 + 0x240 = 0x4240
0x1108 (x)1 (data)0x1080x108 น้อยกว่า 0x500 ✓0 + 0x108 = 0x108
0x0360 (strlen)0 (code)0x360✓0x4360
0x16001 (data)0x6000x600 ไม่น้อยกว่า 0x500 ✗exception
0x20042 (heap)0x004segment ยังไม่ถูกจอง ✗exception

วิธีแยก: เลขฐานสิบหกหลักแรกบอก segment # (เพราะ offset กิน 12 bit = 3 หลักพอดี) 0x1108 → หลักแรก 1, ที่เหลือ 0x108

โปรแกรมในสไลด์มีคำสั่ง jump 360 ซึ่งเป็น virtual address: โปรแกรมไม่ต้องรู้ว่าจริง ๆ แล้ว strlen อยู่ที่ 0x4360

ข้อดีข้อเสีย
share code/data segment ระหว่าง process ได้จัดการ memory ซับซ้อน: ต้องหาที่ว่างขนาดเฉพาะเจาะจง
กัน code segment จากการถูกเขียนทับได้อาจต้อง จัดเรียง memory ใหม่ เป็นครั้งคราวเพื่อหาที่ให้ segment ใหม่หรือ segment ที่โตขึ้น
ขยาย stack/heap ได้อย่าง transparentExternal fragmentation: ที่ว่างเสียเปล่าระหว่างก้อน
ตรวจได้ว่าต้อง copy-on-write หรือไม่

External fragmentation: segment มีขนาดต่างกัน เมื่อจองและคืนไปนาน ๆ ที่ว่างจะแตกเป็นช่องเล็ก ๆ กระจายอยู่ รวมกันแล้วพอ แต่ไม่มีช่องใดใหญ่พอสำหรับ segment ใหม่

วิธีที่ 3: Paging

แก้ fragmentation ด้วยการทำให้ ทุกก้อนขนาดเท่ากัน

  • จัดการ memory เป็นหน่วยขนาดคงที่ เรียกว่า page (ฝั่ง physical เรียก page frame)
  • หา page ว่างง่าย: ใช้ bitmap เช่น 0011111100000001100 — หนึ่ง bit ต่อหนึ่ง physical page frame
  • แต่ละ process มี page table ของตัวเอง เก็บใน physical memory
  • hardware register: pointer ไปยังจุดเริ่มของ page table และ page table length

virtual address แบ่งเป็น page # กับ offset

text
1. แยก virtual address → page #, offset
2. เปิด page table แถวที่ page #  →  ได้ frame # (และสิทธิ์การเข้าถึง)
3. physical address = frame # ต่อด้วย offset  (= frame # × ขนาด page + offset)

offset ไม่ถูกแปลง ใช้ค่าเดิม เพราะ page กับ frame ขนาดเท่ากัน

ตัวอย่างจากสไลด์

page ขนาด 4 byte process มีข้อมูล A–L (3 page) และ page table เป็น [4, 3, 1]

page #virtual addressเนื้อหาframe #physical address
00–3A B C D416–19
14–7E F G H312–15
28–11I J K L14–7

หาตำแหน่งจริงของ F (virtual address 5):

  1. page # = 5 ÷ 4 = 1, offset = 5 mod 4 = 1
  2. page table แถว 1 → frame 3
  3. physical = 3 × 4 + 1 = 13

ใน physical memory page เรียงกลับลำดับ (I–L อยู่ก่อน E–H อยู่ก่อน A–D) และมี frame ของ process อื่นแทรกอยู่ แต่ process เห็นเป็น A ถึง L ต่อเนื่อง

ขั้นที่ 1 / 15เริ่มต้น
วิธี

r = อ่าน, w = เขียน, x = execute ตามด้วย address (ฐานสิบ หรือ 0x ฐานสิบหก)

ชื่อ start length สิทธิ์ (r, w, x) — segment ที่ยังไม่จองเขียนว่า heap -

จำนวน bit ของ offset
12
  1. x 0x240
  2. r 0x1108
  3. w 0x240
  4. r 0x2004
  5. r 0x1600

virtual address

0x240

00001001000000

#segmentstartlengthสิทธิ์
0code0x40000x700rx
1data0x00x500rw
2heap–––
3stack0x20000x1000rw
✕ = exceptionเลข 0x = ฐานสิบหก
1.0×

คำอธิบายทีละขั้น

สถานะเริ่มต้น

Segmentation: virtual address แบ่งเป็นหมายเลข segment กับ offset แต่ละ segment มี start, length และสิทธิ์การเข้าถึงของตัวเองใน segment table กด step เพื่อแปล address ทีละขั้น

ข้อเสียของ paging

สไลด์ถามไว้โดยไม่ได้ให้คำตอบตรง ๆ แต่หน้าถัดไปตอบเอง: page table ใหญ่เกินไปเมื่อ address space กว้าง ต้องมีหนึ่งแถวต่อทุก virtual page แม้ page นั้นจะไม่ได้ใช้ (บทถัดไป)

ตัวอย่างไล่ทีละขั้น

โจทย์: ระบบ paging มี page ขนาด 4 KB (offset 12 bit) page table ของ process: page 0 → frame 5, page 1 → frame 2, page 3 → frame 7 แปลง virtual address 0x1A3C และ 0x3FFF

0x1A3C:

  1. offset 12 bit = เลขฐานสิบหก 3 หลักท้าย → page # = 0x1 = 1, offset = 0xA3C
  2. page 1 → frame 2
  3. physical = frame ต่อด้วย offset = 0x2A3C

0x3FFF:

  1. page # = 3, offset = 0xFFF
  2. page 3 → frame 7
  3. physical = 0x7FFF

ถ้าเป็น 0x2010: page # = 2 ซึ่งไม่มีในตาราง (invalid) → exception

เทียบสามวิธี

Base & BoundsSegmentationPaging
หน่วยทั้ง process ก้อนเดียวsegment ขนาดต่างกันpage ขนาดคงที่
address แบ่งเป็นไม่แบ่งsegment # + offsetpage # + offset
ตารางregister 2 ตัวsegment table (start, length, สิทธิ์)page table (frame, สิทธิ์)
ตรวจขอบvirtual กับ boundoffset กับ lengthpage # กับ page table length
share ได้✗✓ ระดับ segment✓ ระดับ page
กัน code ถูกเขียนทับ✗✓✓
external fragmentationมี (ทั้งก้อน)มีไม่มี
หาที่ว่างยากยาก (ต้องขนาดพอดี)ง่าย (bitmap)
ปัญหาหลักไม่ยืดหยุ่นfragmentationpage table ใหญ่

จุดที่มักพลาด

1. ตรวจ bound ด้วย physical address

ตรวจกับ virtual address (หรือ offset) ก่อนบวก base เสมอ

2. บวก offset กับ frame # ตรง ๆ

ต้องคูณ frame # ด้วยขนาด page ก่อน (หรือคิดเป็นการเอา bit มาต่อกัน)

3. แปลง offset ด้วย

offset ไม่เปลี่ยน สิ่งที่ถูกแปลงคือ page # → frame #

4. คิดว่า offset เท่ากับ length แล้วยังผ่าน

เงื่อนไขคือ offset ต้อง น้อยกว่า length ถ้าเท่ากันก็เลยขอบแล้ว (offset เริ่มที่ 0)

5. สลับ external fragmentation

เป็นปัญหาของ segmentation paging แก้ได้เพราะทุกก้อนเท่ากัน

6. คิดว่า page table ใช้ร่วมกันทุก process

แต่ละ process มี page table ของตัวเอง

ที่มา: 07-address_v4.pdf หน้า 2–22