进程和线程我们先从 Linux 的进程谈起,操作系统要运行一个可执行程序,首先要将程序文件加载到内存,然后 CPU 去读取和执行程序指令,而一个进程就是“一次程序的运行过程”,内核会给每一个进程创建一个名为task_struct的数据结构,而内核也是一段程序,系统启动时就被加载到内存中了。
[root@docker ~]# ls /boot/
config-3.10.0-693.el7.x86_64 grub2 initramfs-4.19.20-1.el7.x86_64.img System.map-3.10.0-693.el7.x86_64 vmlinuz-3.10.0-693.el7.x86_64
config-4.19.20-1.el7.x86_64 initramfs-0-rescue-b2942a79696a4216b528ab0e9c10f754.img initrd-plymouth.img System.map-4.19.20-1.el7.x86_64 vmlinuz-4.19.20-1.el7.x86_64
efi initramfs-0-rescue-ebe1e1e21734302f83dc1a22a78a1851.img symvers-3.10.0-693.el7.x86_64.gz vmlinuz-0-rescue-b2942a79696a4216b528ab0e9c10f754
grub initramfs-3.10.0-693.el7.x86_64.img symvers-4.19.20-1.el7.x86_64.gz vmlinuz-0-rescue-ebe1e1e21734302f83dc1a22a78a1851
进程在运行过程中要访问内存,而物理内存是有限的,比如 16GB,那怎么把有限的内存分给不同的进程使用呢?跟 CPU 的分时共享一样,内存也是共享的,Linux 给每个进程虚拟出一块很大的地址空间,比如 32 位机器上进程的虚拟内存地址空间是 4GB,从 0x00000000 到 0xFFFFFFFF。
但这 4GB 并不是真实的物理内存,而是进程访问到了某个虚拟地址,如果这个地址还没有对应的物理内存页,就会产生缺页中断,分配物理内存,MMU(内存管理单元)会将虚拟地址与物理内存页的映射关系保存在页表中,再次访问这个虚拟地址,就能找到相应的物理内存页。每个进程的这 4GB 虚拟地址空间分布如下图所示: