memory-management

OS Abstraction

  • Virtual Memory: an address space can be larger than the machine’s physical memory
  • Address Independence: same numeric address can be used in different address spaces (i.e., different processes), yet remain logically distinct
  • Protection: one process can’t access data in another process’s address space (actually controlled sharing)

Memory translation

Uniprogramming: One process a time

  • No virtual memory
  • Address independence: yes
  • Protection: yes
  • Pro: Simple
  • Con: Expensive context switch

Multiprogramming: Many processes share physical memory

  • static address translation: linker-loader adds offset->register values calculate addr(app takes last move) - expensive & security issues
  • dynamic address translation: hardware(MMU) translation, invoke faults(OS takes last move)

1. Techniques

  • Base and bounds:
    Use continuous chunk of memory, store/change “base” and “bound” when context switch
    • translation: check offset -> base+offset
    • context switch: change base and bound
    • pros: simple, fast
    • cons: no virtual address, no data sharing, external fragmentation
  • Segmentation:
    Use many continuous chunk of memory, each is one “segment”
    • translation: look for segment# -> check offset -> base+offset
    • context switch: segment table
    • pros: data sharing, grow segment(separately)
    • cons: few virtual address(expensive), external fragmentation
  • Paging:
    Use page as a fixed-sized memory unit
    • translation: page table register -> page table -> page
    • context switch: change page table register
    • pros: flexible sharing, virtual memory, easy to grow address space
    • cons: large page tables
    • page size: 4K/8K(compromise) too large: internal fragmentation; too small: even larger page table

2. Efficiency

  • Multi-level paging: Using tree structure to represent sparse virtual address space, but need multiple levels of lookups in translation
  • Cache: TLB->Cache virtual->physical mapping entries. If miss: look up in multi-level paging tree. context switch: need to flush TLB
  • Replacement: Not all valid pages may fit in physical memory. Some pages must be paged out (written) to disk when reading in a new page from disk. GOAL: minimize page faults
    • FIFO: simple but not optimal
    • LRU: assume past predicts the future, hard to implement. approximation: clock algorithm.

3. other features

  • page table entries: (physical page#, resident, protection(read enable, write enable), dirty, referenced, shared bits, maintained by MMU or by OS) simplest MMU: only physical page number, read enable and write enable
  • zero-on reference:
  • copy on write: add reference count to each page, copying to a new page only when written

Kernel memory

  • dual mode:
    • kernel mode: Use kernel address space (always pinned in physical memory), have top privileges
    • user mode: Process’ address space. Limited privileges.
    • user mode -> kernel mode: system calls, faults, interrupts
  • system calls:
    • Arguments: copy from user’s address space to kernel’s address space. Also have to validate (not make kernel crash)
    • fork(): create a copy of the parent address space. Use copy on write to defer work. Return 0 if it’s child process. Otherwise return child’s process id.
    • exec(): put the program image to memory and execute the program. Use memory-mapped files to optimize (do not have to load all of the codes to disk immediately (on demand), and one piece of code can be shared by all process instances)
    • waitpid(): wait for another process to finish
    • pipe(fd[2]): For interprocess communication. fd[0] is the reader, fd[1] is the writer. pipe exists only in the creator’s address space.
    • dup2(int oldfd, int new fd): copy a file descriptor
    • mmap()
    • mprotect()
    • signal()