text segment(文本段):包含进程运行的机器指令
initiallized data segment(初始化数据段):包含显式初始化的全局变量和静态变量
uninitiallized data segment(未初始化数据段):包含未显式初始化的全局变量和静态变量
stack(栈):动态增长和收缩,由stack frames(栈帧)组成
heap(堆):运行时动态分配,堆顶为program break
虚拟内存管理(空间局部性,时间局部性):
将内存划分为page(页)。
每个程序仅有部分分页驻留在物理内存,构成了resident set(驻留集)。未使用的页保存在swap area(交换区)。
交换区是磁盘保留区域,需要时载入物理内存。进程访问的页不再物理内存,发送page fault,内核挂起进程执行,并从磁盘将页面载入。
内核为每个进程维护一张page table(页表)
command-line arguments(argc,argv)命令行参数
environment list环境列表,程序执行时载入用户或系统设置的变量
setjmp,longjmp:跳转将此时的环境(此时栈的位置,pc,寄存器等数据保存)保存(动作类似于函数压栈,不过是压入特殊位置,跳到特殊位置),跳转到其他位置,并在跳回来恢复。
内存分配:
调整program break:
int brk(void *end_data_segment);//program break设置为end_data_segment处
void* sbrk(intptr_t increment);program break增加increment
malloc(),free(),calloc(),realloc(),
memalign(),posix_memalign();//分配对齐的内存
alloca()在堆栈上分配
内存分配上也可能出现内存泄漏,因此可以使用glibc的malloc调试工具和调试库valgrind等等
内存分配上也可能出现内存碎片,可以针对程序使用不同的分配策略(如C++ new的多层分配策略)
进程控制:
fork();//返回两次,一次在子进程内返回0,一次在父进程内返回子进程pid;
进程fork,子进程和其共享页,其中代码段可读无法修改,其余部分COW(写时复制)
vfork();//补位子进程复制页表,虚拟内存页,共享父进程,直到成功exec(),_exit()退出;在子进程exec()或_exit()之前暂停执行父进程
_exit(status);//定义终止状态后终止
exit(status),//先后调用退出处理程序,刷新stdio流缓冲,调用_exit()
退出处理程序:atexit();注册,glibc提供了带参数的退出处理on_exit();
其中退出处理程序的执行顺序与调用顺序相反
wait(int * status);//阻塞到子进程终止,将终止信息通过status指向的整形变量返回
waitpid(pid, int* status, int option);//根据pid值得不同,标识等待不同的子进程。
同时,还有使用一组宏判断status。详见wait
waitid();//linux2.6.9加入
wait3();wait4();//
孤儿进程:当父进程终止后,子进程的父进程变为ID为1的init进程;
僵尸进程:当父进程尚未调用wait()之前子进程终止,该子进程尚未被清理被称为僵尸进程(释放大部分资源);
SIGCHLD为子进程终止时限父进程发送的信号
execve():详见man
exec()之后,文件描述符会保留
system()函数执行shell命令