操作系统进程、分页与内存分配相关技术问题咨询
进程与内存管理相关问题解答
关于进程换出辅存的疑问
进程创建后,若LTS决定将其换入辅存,是否会将所有上述数据结构都复制到如SSD这类存储介质中?还是仅复制text、data段,PCB保留在内核空间中?
你描述的实际是长期调度器(LTS/作业调度器)将暂时不具备运行条件的进程换出到辅存的场景,对应的处理规则如下:
- PCB会永久驻留在内核空间内存中,不会被换出到辅存,内核需要始终持有PCB来维护进程的基础状态、资源持有记录等核心元数据
- 用户态的text、data、heap、用户栈会被整体或者按页换出到辅存的交换分区/交换文件中
- 内核栈的处理分场景:如果进程已经陷入内核态还未返回用户态,不会被换出;如果进程完全处于用户态阻塞,内核栈可以和用户态内存一起被换出
分页机制相关疑问解答
1. 非法内存访问的检测与异常处理
- 内核判断非法访问的核心依据是进程地址空间的VMA(虚拟内存区域)结构体,每个进程的PCB中都维护了属于自身的VMA链表/红黑树,记录了所有合法虚拟地址区间的属性(可读/可写/可执行、属于栈/堆/代码段等)
- 当CPU访问虚拟地址时,首先查TLB,未命中则查页表,如果页表中没有对应有效页表项,会触发缺页异常,CPU立即陷入内核态执行缺页异常处理函数,不会延后到进程切换时
- 处理函数首先会比对目标地址是否在进程的合法VMA区间内:如果不在,直接判定为非法访问,立即给进程发送
SIGSEGV信号终止进程
2. 栈溢出的检测逻辑
- 你提到的“内核在PCB中存储连续虚拟地址空间指针,检查栈顶和堆是否触碰”的逻辑不符合现代操作系统的实现:当前系统进程的地址空间是非连续的,栈和堆之间还有大量未分配的虚拟地址区间,二者不会直接触碰
- 内核在VMA中记录了用户栈的起始地址、最大允许大小以及栈的增长方向:当栈指针(SP)往下超过当前栈VMA的下界时,首先触发缺页异常,内核会检查这个地址是否在栈的最大允许增长范围内,如果是就自动拓展栈的VMA、分配物理页;如果超过了最大栈大小限制,就判定为栈溢出,发送
SIGSEGV信号
3. 程序内部地址的生成逻辑
- 程序本身的地址是编译链接时确定的,现代编译器默认生成位置无关可执行文件(PIE),程序内使用的都是相对偏移,加载时内核会给进程随机分配虚拟地址空间的基地址,相对偏移加上基地址就得到最终的虚拟地址
- 32位系统的虚拟地址范围确实是
0x00000000~0xFFFFFFFF,64位系统通常只会使用低48位的虚拟地址空间,用户态占低地址一半,内核态占高地址一半,所有用户态程序的虚拟地址空间互相隔离,由内核负责维护页表完成虚拟地址到物理地址的映射
4. 进程终止的流程
- 正常终止:用户程序执行完最后一条业务指令后,会自动调用C标准库的
exit()封装函数,最终触发exit系统调用陷入内核 - 异常终止/被杀死:比如收到不可忽略的终止信号,不管是父进程发送的还是内核发送的,内核会直接强制进程进入内核态,调用内核内部的
do_exit()函数执行终止逻辑,不需要进程主动调用exit系统调用 - 不管哪种终止场景,最终都是内核负责释放进程持有的内存资源、关闭打开的文件、回收PCB等,进程本身只是触发终止流程,资源回收完全由内核完成
5. 三级调度器的调用时机
你提到的三类内核对应不同的调度逻辑,三类调度器的通用调用时机如下:
- 长期调度器(LTS/作业调度器):仅在批处理系统/大型机系统中存在,调用时机是系统当前内存中就绪进程数量不足时,从辅存的作业后备队列中选择符合条件的作业加载到内存,创建进程加入就绪队列,普通桌面/服务器系统一般没有LTS
- 中期调度器(MTS/内存调度器):调用时机是系统内存不足时,选择内存中长时间阻塞的进程,把其内存换出到辅存,腾出内存给其他就绪进程;当内存富余、被换出的进程满足运行条件时,再把它换入内存
- 短期调度器(STS/进程调度器):是最常用的调度器,调用时机包括:进程主动阻塞(调用sleep、等待IO等)、进程时间片耗尽、更高优先级的进程进入就绪队列、进程从系统调用返回用户态时、中断处理完成返回用户态时
6. 堆和栈的页数是否可变
是可变的:
- 栈的最大大小由系统参数限制(Linux下默认是8M),可以通过
ulimit -s命令修改,也可以在程序运行时通过系统调用调整,JVM的-Xss参数就是限制Java线程栈的最大大小,超过这个大小就会触发栈溢出 - 堆的大小是动态变化的,用户程序调用
malloc/new申请内存时,如果当前堆的空闲空间不足,内核会自动拓展堆的VMA区间,分配新的物理页,直到达到进程的虚拟地址空间上限或者系统内存上限
7. 进程写数据时的内存分配逻辑
- 用户态进程写内存的操作是直接操作虚拟地址,首先如果目标地址已经在页表中映射了可写的物理页,就直接写入,不会触发内核操作
- 如果目标地址没有对应的物理页映射,就触发缺页异常,内核首先检查地址是否在合法VMA区间,如果合法就分配对应的物理页,更新页表,然后进程再继续写入操作
- 不需要提前为进程预留空闲页,也不会主动拉长页表,页表是按需分配的,每分配一个新的虚拟页,才会新增对应的页表项
内容的提问来源于stack exchange,提问作者Davide
相关产品推荐
相关产品推荐

