Paging dan Segmentation

Secara sederhana, Paging dan Segmentation adalah dua cara yang digunakan oleh sistem operasi (OS) untuk mengatur bagaimana sebuah program disimpan di dalam memori fisik (RAM). Bayangkan RAM sebagai sebuah rak buku besar dan program Anda sebagai sebuah buku.


Paging: Membagi Memori Menjadi "Halaman" Berukuran Sama

Paging adalah teknik manajemen memori yang memecah program dan memori fisik menjadi blok-blok berukuran sama (fixed-size).

  • Blok-blok pada program disebut Pages (halaman).

  • Blok-blok pada memori fisik (RAM) disebut Frames (bingkai).

Intuisi / Analogi Sederhana: 📖

Bayangkan Anda memiliki sebuah buku cerita (program) yang sangat tebal. Rak buku Anda (RAM) memiliki banyak slot kosong, tapi tidak ada satu slot pun yang cukup besar untuk menampung seluruh buku secara utuh.

Dengan Paging, Anda melakukan ini:

  1. Anda merobek buku cerita menjadi halaman-halaman terpisah dengan ukuran yang sama persis (ini adalah Pages).

  2. Anda meletakkan halaman-halaman ini secara acak di slot-slot kosong mana pun yang tersedia di rak buku (ini adalah Frames). Halaman 1 bisa ada di slot 5, halaman 2 di slot 1, halaman 3 di slot 8, dan seterusnya. Mereka tidak perlu berurutan.

  3. Agar tidak bingung, Anda membuat sebuah Daftar Isi khusus yang disebut Page Table. Daftar ini mencatat: "Halaman 1 ada di slot 5", "Halaman 2 ada di slot 1", dan seterusnya.

Bagaimana Cara Kerjanya? (Proses Translasi Alamat)

Ketika CPU ingin membaca instruksi tertentu (misalnya, "baca baris ke-5 dari halaman 3"), prosesnya adalah:

  1. Alamat Logis: CPU memberikan alamat logis yang terdiri dari dua bagian: Nomor Halaman (Page Number) dan Offset (posisi baris di dalam halaman itu). Contoh: (Page 3, Offset 5).

  2. Mencari di Tabel Halaman (Page Table): Sistem operasi melihat Page Table untuk mencari tahu di frame (slot) mana Page 3 disimpan. Misalkan, tabel mengatakan Page 3 ada di Frame 8.

  3. Membentuk Alamat Fisik: Sistem operasi menggabungkan nomor frame dengan offset untuk mendapatkan alamat fisik di RAM. Jadi, alamatnya menjadi (Frame 8, Offset 5). Komputer pun langsung menuju ke slot 8 di rak buku dan membaca baris ke-5.

Kelebihan Paging:

  • Menghilangkan Fragmentasi Eksternal: Karena semua "slot" (frame) berukuran sama, tidak akan ada sisa-sisa ruang kosong yang aneh dan tidak bisa digunakan di antara program. Setiap slot kosong pasti bisa diisi oleh halaman mana pun.

  • Alokasi Memori Sederhana: OS hanya perlu mencari frame kosong mana saja, tanpa perlu pusing mencari blok memori yang cukup besar dan berurutan.

  • Sangat Efisien untuk Virtual Memory: Konsep ini memudahkan OS untuk memindahkan halaman yang jarang dipakai ke disk (hard drive) untuk sementara waktu.


Segmentation: Membagi Memori Berdasarkan "Segmen" Logis

Segmentation adalah teknik yang membagi memori menjadi blok-blok berukuran bervariasi (variable-sized) yang disebut segmen. Pembagian ini didasarkan pada struktur logis dari sebuah program.

Intuisi / Analogi Sederhana: 🗂️

Bayangkan sebuah proyek besar (program) yang terdiri dari beberapa bagian: tumpukan kode program, tumpukan data variabel, gambar-gambar, dan tumpukan fungsi pustaka (library).

Dengan Segmentation, Anda melakukan ini:

  1. Anda tidak memotong-motong proyek, melainkan mengelompokkannya ke dalam folder-folder terpisah berdasarkan fungsinya (ini adalah Segments). Jadi ada "Folder Kode", "Folder Data", "Folder Gambar", dll. Setiap folder ini ukurannya bisa berbeda-beda.

  2. Anda meletakkan seluruh folder ini di dalam lemari arsip (RAM). "Folder Kode" yang besar mungkin butuh satu laci penuh, sementara "Folder Gambar" yang kecil hanya butuh sebagian kecil dari laci lain.

  3. Anda membuat Label di Depan Lemari yang disebut Segment Table. Label ini mencatat: "Folder Kode dimulai dari alamat 1000 dan ukurannya 500 baris", "Folder Data dimulai dari alamat 2000 dan ukurannya 150 baris", dst.

Bagaimana Cara Kerjanya? (Proses Translasi Alamat)

Ketika CPU ingin mengakses sesuatu (misalnya, "variabel ke-10 di dalam segmen data"), prosesnya adalah:

  1. Alamat Logis: CPU memberikan alamat logis yang terdiri dari: Nomor Segmen (Segment Number) dan Offset (posisi di dalam segmen itu). Contoh: (Segment Data, Offset 10).

  2. Mencari di Tabel Segmen (Segment Table): Sistem operasi melihat Segment Table untuk Segment Data. Tabel ini memberikan dua informasi penting: Alamat Awal (Base Address) di mana segmen itu dimulai di RAM (misal, 2000) dan Ukuran (Limit) dari segmen itu (misal, 150).

  3. Pengecekan Keamanan & Membentuk Alamat Fisik:

    • Pertama, OS mengecek apakah offset (10) lebih kecil dari limit (150). Jika ya, aksesnya aman. Jika tidak (misalnya mencoba mengakses offset 200), akan terjadi error karena mencoba mengakses memori di luar segmen yang seharusnya.

    • Jika aman, alamat fisik dihitung dengan menjumlahkan alamat awal dengan offset: Alamat Fisik = Base Address + Offset (2000 + 10 = 2010). Komputer pun langsung menuju ke alamat 2010 di RAM.

Kelebihan Segmentation:

  • Pemisahan Logis: Cara ini sangat sesuai dengan cara pandang programmer. Programmer berpikir dalam bentuk "kode", "data", "stack", bukan "halaman 27".

  • Memfasilitasi Proteksi dan Berbagi (Sharing): Sangat mudah untuk melindungi segmen. Misalnya, segmen kode bisa ditandai sebagai read-only (hanya bisa dibaca). Selain itu, jika beberapa program menggunakan pustaka (library) yang sama, mereka bisa berbagi satu segmen kode yang sama di memori, sehingga lebih hemat.

  • Manajemen Struktur Data yang Dinamis: Struktur data seperti stack yang bisa membesar dan mengecil lebih mudah dikelola sebagai satu segmen tersendiri.


Tentu, kita bisa membuat simulasi sederhana dari Paging dan Segmentation menggunakan bahasa Go (Golang).

Simulasi ini akan fokus pada proses translasi alamat (mengubah alamat logis dari CPU menjadi alamat fisik di RAM) untuk menunjukkan perbedaan fundamental antara keduanya. Ini bukan implementasi level sistem operasi, melainkan model konseptual dalam bentuk kode.

Struktur Proyek

Kita akan membuat satu file main.go yang berisi kedua simulasi.


Simulasi Paging di Go

Konsep Kunci:

  • Memori fisik dibagi menjadi Frames berukuran sama.

  • Program dibagi menjadi Pages dengan ukuran yang sama seperti Frame.

  • Page Table memetakan setiap Page ke sebuah Frame di memori fisik.

  • Alamat Fisik = (Nomor Frame * Ukuran Page) + Offset

// main.go
package main

import (
	"fmt"
)

// --- Bagian 1: Simulasi Paging ---

const (
	PAGE_SIZE   = 16 // Ukuran setiap page/frame adalah 16 byte (untuk simplisitas)
	MEMORY_SIZE = 128 // Total ukuran memori fisik kita 128 byte
)

// PhysicalMemory merepresentasikan RAM kita
type PhysicalMemory [MEMORY_SIZE]byte

// PageTable untuk melacak di frame mana setiap page berada
// Key: nomor page, Value: nomor frame
type PageTable map[int]int

// PagingSystem menyatukan semua komponen
type PagingSystem struct {
	Memory    *PhysicalMemory
	PageTable PageTable
}

// initPagingSystem menyiapkan simulasi paging
func initPagingSystem() *PagingSystem {
	fmt.Println("--- Memulai Simulasi Paging ---")
	mem := new(PhysicalMemory)
	pt := make(PageTable)

	// Anggaplah kita memuat sebuah program yang memiliki 3 halaman (pages)
	// Kita letakkan secara tidak berurutan di memori fisik (frames)
	// Page 0 -> Frame 5
	// Page 1 -> Frame 2
	// Page 2 -> Frame 7
	pt[0] = 5
	pt[1] = 2
	pt[2] = 7

	// Mari kita isi beberapa data dummy ke dalam memori fisik untuk representasi
	// Isi data untuk Page 0 di Frame 5
	copy(mem[5*PAGE_SIZE:], []byte("Ini adalah Page 0"))
	// Isi data untuk Page 1 di Frame 2
	copy(mem[2*PAGE_SIZE:], []byte("Ini adalah Page 1"))
	// Isi data untuk Page 2 di Frame 7
	copy(mem[7*PAGE_SIZE:], []byte("Ini adalah Page 2"))

	fmt.Printf("Konfigurasi Awal:\n")
	fmt.Printf("  - Page 0 dimuat ke Frame 5 (Alamat Fisik: %d)\n", 5*PAGE_SIZE)
	fmt.Printf("  - Page 1 dimuat ke Frame 2 (Alamat Fisik: %d)\n", 2*PAGE_SIZE)
	fmt.Printf("  - Page 2 dimuat ke Frame 7 (Alamat Fisik: %d)\n\n", 7*PAGE_SIZE)

	return &PagingSystem{
		Memory:    mem,
		PageTable: pt,
	}
}

// translateAddress menerjemahkan alamat logis ke alamat fisik
func (ps *PagingSystem) translateAddress(logicalAddress int) (int, error) {
	pageNumber := logicalAddress / PAGE_SIZE
	offset := logicalAddress % PAGE_SIZE

	fmt.Printf("Menerjemahkan Alamat Logis %d:\n", logicalAddress)
	fmt.Printf("  - Nomor Page: %d / %d = %d\n", logicalAddress, PAGE_SIZE, pageNumber)
	fmt.Printf("  - Offset: %d %% %d = %d\n", logicalAddress, PAGE_SIZE, offset)

	frameNumber, ok := ps.PageTable[pageNumber]
	if !ok {
		return 0, fmt.Errorf("Page Fault! Page %d tidak ada di Page Table.", pageNumber)
	}

	physicalAddress := (frameNumber * PAGE_SIZE) + offset
	fmt.Printf("  - Page Table lookup: Page %d ada di Frame %d\n", pageNumber, frameNumber)
	fmt.Printf("  - Alamat Fisik: (%d * %d) + %d = %d\n", frameNumber, PAGE_SIZE, offset, physicalAddress)
	return physicalAddress, nil
}

// --- Akhir Bagian 1 ---

func main() {
	// Menjalankan simulasi Paging
	pagingSystem := initPagingSystem()
	testPagingAddresses := []int{20, 35, 50} // Alamat-alamat logis yang akan diuji

	for _, addr := range testPagingAddresses {
		pAddr, err := pagingSystem.translateAddress(addr)
		if err != nil {
			fmt.Printf("  -> ERROR: %v\n\n", err)
		} else {
			fmt.Printf("  -> Sukses! Alamat Fisik adalah %d\n\n", pAddr)
		}
	}
    
    // Kita akan menambahkan simulasi segmentasi di sini nanti
}

Penjelasan Kode Paging:

  1. Konstanta: PAGE_SIZE dan MEMORY_SIZE mendefinisikan arsitektur sistem kita. Ukuran page dan frame adalah sama (16 bytes).

  2. Struktur Data: PhysicalMemory adalah array byte sederhana yang berperan sebagai RAM. PageTable adalah sebuah map yang menjadi "daftar isi" kita.

  3. initPagingSystem: Fungsi ini menyiapkan simulasi. Kita berpura-pura memuat program 3 halaman ke dalam frame yang acak (5, 2, 7) untuk menunjukkan bahwa alokasi tidak harus berurutan.

  4. translateAddress: Ini adalah inti dari simulasi.

    • Ia mengambil logicalAddress.

    • Membaginya dengan PAGE_SIZE untuk mendapatkan pageNumber.

    • Menggunakan operator modulo (%) untuk mendapatkan offset.

    • Mencari pageNumber di PageTable untuk mendapatkan frameNumber.

    • Menghitung alamat fisik akhir.


Simulasi Segmentation di Go

Konsep Kunci:

  • Memori dibagi berdasarkan segmen logis (kode, data, dll.) dengan ukuran bervariasi.

  • Segment Table menyimpan alamat awal (Base) dan ukuran (Limit) dari setiap segmen.

  • Ada pengecekan keamanan: Offset harus lebih kecil dari Limit.

  • Alamat Fisik = Alamat Base + Offset

Mari kita tambahkan kode berikut ke file main.go kita.

// main.go (Lanjutan)
// ... (kode paging dari atas) ...

// --- Bagian 2: Simulasi Segmentation ---

// SegmentEntry menyimpan informasi tentang satu segmen
type SegmentEntry struct {
	Base  int // Alamat awal di memori fisik
	Limit int // Ukuran dari segmen
}

// SegmentTable untuk melacak setiap segmen
// Key: nomor segmen, Value: informasi Base dan Limit
type SegmentTable map[int]SegmentEntry

// SegmentationSystem menyatukan semua komponen
type SegmentationSystem struct {
	Memory       *PhysicalMemory
	SegmentTable SegmentTable
}

// initSegmentationSystem menyiapkan simulasi segmentasi
func initSegmentationSystem() *SegmentationSystem {
	fmt.Println("\n--- Memulai Simulasi Segmentation ---")
	// Kita bisa gunakan memori yang sama atau buat baru. Mari buat baru agar bersih.
	mem := new(PhysicalMemory)
	st := make(SegmentTable)

	// Anggaplah kita memuat program dengan 3 segmen logis
	// Segmen 0: KODE (ukuran 30 byte), dimulai dari alamat 50
	// Segmen 1: DATA (ukuran 20 byte), dimulai dari alamat 90
	// Segmen 2: STACK (ukuran 25 byte), dimulai dari alamat 15
	st[0] = SegmentEntry{Base: 50, Limit: 30}
	st[1] = SegmentEntry{Base: 90, Limit: 20}
	st[2] = SegmentEntry{Base: 15, Limit: 25}

	// Isi data dummy
	copy(mem[50:], []byte("...kode program ada di sini..."))
	copy(mem[90:], []byte("...variabel data..."))
	copy(mem[15:], []byte("...data stack..."))

	fmt.Println("Konfigurasi Awal:")
	fmt.Printf("  - Segmen 0 (KODE): Base=%d, Limit=%d\n", st[0].Base, st[0].Limit)
	fmt.Printf("  - Segmen 1 (DATA): Base=%d, Limit=%d\n", st[1].Base, st[1].Limit)
	fmt.Printf("  - Segmen 2 (STACK): Base=%d, Limit=%d\n\n", st[2].Base, st[2].Limit)

	return &SegmentationSystem{
		Memory:       mem,
		SegmentTable: st,
	}
}

// translateAddress menerjemahkan alamat logis (segmen, offset) ke alamat fisik
func (ss *SegmentationSystem) translateAddress(segmentNumber, offset int) (int, error) {
	fmt.Printf("Menerjemahkan Alamat Logis (Segmen: %d, Offset: %d):\n", segmentNumber, offset)

	segment, ok := ss.SegmentTable[segmentNumber]
	if !ok {
		return 0, fmt.Errorf("Segment Fault! Segmen %d tidak ada di Segment Table.", segmentNumber)
	}
	fmt.Printf("  - Segment Table lookup: Segmen %d ditemukan (Base: %d, Limit: %d)\n", segmentNumber, segment.Base, segment.Limit)

	// Pengecekan keamanan yang krusial!
	if offset >= segment.Limit {
		return 0, fmt.Errorf("Protection Fault! Offset %d di luar batas (Limit: %d).", offset, segment.Limit)
	}
	fmt.Println("  - Cek Keamanan: Offset < Limit -> OK")

	physicalAddress := segment.Base + offset
	fmt.Printf("  - Alamat Fisik: %d (Base) + %d (Offset) = %d\n", segment.Base, offset, physicalAddress)
	return physicalAddress, nil
}

// --- Akhir Bagian 2 ---

// Tipe data untuk pengujian segmentasi
type logicalAddressSeg struct {
	segment int
	offset  int
}

func main() {
	// Menjalankan simulasi Paging
	pagingSystem := initPagingSystem()
	testPagingAddresses := []int{20, 35, 50} // Alamat-alamat logis yang akan diuji

	for _, addr := range testPagingAddresses {
		pAddr, err := pagingSystem.translateAddress(addr)
		if err != nil {
			fmt.Printf("  -> ERROR: %v\n\n", err)
		} else {
			fmt.Printf("  -> Sukses! Alamat Fisik adalah %d\n\n", pAddr)
		}
	}

	// Menjalankan simulasi Segmentation
	segmentationSystem := initSegmentationSystem()
	testSegmentationAddresses := []logicalAddressSeg{
		{segment: 0, offset: 10},  // Akses valid ke segmen KODE
		{segment: 1, offset: 19},  // Akses valid ke segmen DATA (di batas akhir)
		{segment: 0, offset: 35},  // Akses ILEGAL ke segmen KODE (offset > limit)
		{segment: 3, offset: 5},   // Akses ILEGAL (segmen tidak ada)
	}

	for _, addr := range testSegmentationAddresses {
		pAddr, err := segmentationSystem.translateAddress(addr.segment, addr.offset)
		if err != nil {
			fmt.Printf("  -> ERROR: %v\n\n", err)
		} else {
			fmt.Printf("  -> Sukses! Alamat Fisik adalah %d\n\n", pAddr)
		}
	}
}

Cara Menjalankan

  1. Simpan seluruh kode gabungan di atas dalam satu file bernama main.go.

  2. Buka terminal atau command prompt.

  3. Arahkan ke direktori tempat Anda menyimpan file tersebut.

  4. Jalankan perintah: go run main.go

Hasil yang Diharapkan (Output)

--- Memulai Simulasi Paging ---
Konfigurasi Awal:
  - Page 0 dimuat ke Frame 5 (Alamat Fisik: 80)
  - Page 1 dimuat ke Frame 2 (Alamat Fisik: 32)
  - Page 2 dimuat ke Frame 7 (Alamat Fisik: 112)

Menerjemahkan Alamat Logis 20:
  - Nomor Page: 20 / 16 = 1
  - Offset: 20 % 16 = 4
  - Page Table lookup: Page 1 ada di Frame 2
  - Alamat Fisik: (2 * 16) + 4 = 36
  -> Sukses! Alamat Fisik adalah 36

Menerjemahkan Alamat Logis 35:
  - Nomor Page: 35 / 16 = 2
  - Offset: 35 % 16 = 3
  - Page Table lookup: Page 2 ada di Frame 7
  - Alamat Fisik: (7 * 16) + 3 = 115
  -> Sukses! Alamat Fisik adalah 115

Menerjemahkan Alamat Logis 50:
  - Nomor Page: 50 / 16 = 3
  - Offset: 50 % 16 = 2
  -> ERROR: Page Fault! Page 3 tidak ada di Page Table.

--- Memulai Simulasi Segmentation ---
Konfigurasi Awal:
  - Segmen 0 (KODE): Base=50, Limit=30
  - Segmen 1 (DATA): Base=90, Limit=20
  - Segmen 2 (STACK): Base=15, Limit=25

Menerjemahkan Alamat Logis (Segmen: 0, Offset: 10):
  - Segment Table lookup: Segmen 0 ditemukan (Base: 50, Limit: 30)
  - Cek Keamanan: Offset < Limit -> OK
  - Alamat Fisik: 50 (Base) + 10 (Offset) = 60
  -> Sukses! Alamat Fisik adalah 60

Menerjemahkan Alamat Logis (Segmen: 1, Offset: 19):
  - Segment Table lookup: Segmen 1 ditemukan (Base: 90, Limit: 20)
  - Cek Keamanan: Offset < Limit -> OK
  - Alamat Fisik: 90 (Base) + 19 (Offset) = 109
  -> Sukses! Alamat Fisik adalah 109

Menerjemahkan Alamat Logis (Segmen: 0, Offset: 35):
  - Segment Table lookup: Segmen 0 ditemukan (Base: 50, Limit: 30)
  -> ERROR: Protection Fault! Offset 35 di luar batas (Limit: 30).

Menerjemahkan Alamat Logis (Segmen: 3, Offset: 5):
  -> ERROR: Segment Fault! Segmen 3 tidak ada di Segment Table.

Kesimpulan dari Simulasi

  • Paging bekerja seperti kalkulator sederhana, memecah alamat logis menjadi page dan offset untuk menemukan frame dan menghitung alamat fisik. Ia tidak peduli dengan struktur program, hanya ukuran blok yang seragam.

  • Segmentation bekerja seperti penjaga keamanan. Ia melihat alamat logis sebagai segmen dan offset, lalu pertama-tama memeriksa izin akses (offset < limit) sebelum menghitung alamat fisik. Ini adalah cerminan dari pandangan logis seorang programmer.

Last updated