为什么同一个程序、同一个地址可以启动很多份?
本讲内容
操作系统中的每个进程都有独立的地址空间
虚拟地址空间设计
内存是分为 “页面” 的
bool vme_init (void *(*alloc)(int), void (*free)(void *));
void protect (AddrSpace *a);
void unprotect (AddrSpace *a);
void map (AddrSpace *a, void *va, void *pa, int prot);
Context *ucontext (AddrSpace *a, Area kstack, void *entry);
实现数据结构好办,就是个 map<uintptr_t,uintptr_t>
map
消耗 $c\cdot n$ 的内存, $c>1$)我们的老朋友:局部性
4GB/4KB = $1024^2$,那就实现成一个 2 层的 1024 叉树。
数据结构实现的技巧
维护一张查找表。
这是可编程 MMU (MIPS)
用一个 hash table 维护 $(x, asid) \to M(x)$ 的映射。
为什么这是可以的?
寄存器其实是地址空间非常小的内存 (mov-regs.S)
实际上,会有更大的 Physical Register File (PRF)
mov $1, %rax
) 会被 “重命名”内存访问符合 Locality of References,“局部性原理”
A phenomenon in which the same values, or related storage locations, are frequently accessed, depending on the memory access pattern.
从另一个角度,根据内存访问的历史,通常能较为准确地预测未来可能访问的内存,并且访问临近内存居多
当内存/cache 越来越大、prefetch 越来越好……
SSD Flash; 磁盘
缓存虚拟地址还是物理地址?
缓存虚拟地址
缓存物理地址
char buf[SIZE];
...
ssize_t nwrite = write(fd, buf, SIZE); // in printf
...
操作系统
buf
里写入*(KERNEL_ADDRESS)
将引发 page fault (SIGSEGV)在地址空间中同时维护操作系统内核与用户进程的内存映射。
例子
0xc0000000-0xffffffff
内存用户进程不可访问 (U-bit = 1)0xc0001234
%eip = 0xc0001234
)复杂系统里有惊喜!
// %rcx: 无权限访问的地址;%rbx: 未载入缓存的数组
xorq %rax, %rax
retry: movzbq (%rcx), %rax // 非法访问;Page Fault
shlq $0xc, %rax
jz retry
movq (%rbx, %rax), %rbx // (%rbx + (%rcx) * 4096)