本章关注单进程运行环境:启动&终止、参数传递和内存布局等。
进程启动终止
如图所示:
- 启动:内核通过exec函数执行程序,在main函数运行之前,会调用启动例程(start-up routine),取得命令行参数和环境变量。可以把启动例程理解为exit(main(argc,argv))。
- 终止:五种正常终止方式(从main方法返回/exit/_exit/最后一个线程返回/最后一个线程退出);三种异常终止方式(abort/接收到信号/最后一个线程接收到取消请求)。
- exit与_exit关系:exit调用_exit方法通知内核退出程序,之前会进行清理工作,包括调用用户通过atexit函数注册的回调方法和标准I/O的fclose函数。
命令行参数和环境变量
main函数原型为:
int main(int argc, char *argv[]);
其中argc为参数个数,argv为参数指针数组,可以通过以下方法访问:
for (i = 0; i <argc; i++) /* echo all command-line args */ printf("argv[%d]: %s\n", i, argv[i]);
环境变量也被传递给程序,环境变量定义在全局指针数组中:
extern char **environ;
可以通过getenv/putenv/setenv/unsetenv等函数访问环境变量
C程序内存布局
如图所示:
- text:程序正文段,通常是只读机器指令。
- initialized data:显示初始化的全局变量
- bss:名称为历史原因(block startedby symbol),C语言未初始化,由内核初始化为0或者null的全局变量。
- heap:堆,动态分配内存,一般向高地址增长。
- stack:栈,保存局部变量,函数参数、返回地址等,一般向低地址增长。
- 使用size命令可以输出text,data,bss段大小。
- 大部分系统都支持共享库,共享库在内存中只需要存在一份,所有进程都可以引用它,其优点是可以减小可执行文件大小,并且共享库能独立升级,使用它的程序不用重新link。
其他重要函数
- 内存分配:malloc/calloc(分配n个大小相同的连续空间)/realloc(重新分配,用于增大或者减小已经分配的内存空间,可能需要移动指针地址)/free(释放空间,指针的值并不会变成NULL,只是这段内存可以重新通过malloc分配)。内存分配通过系统调用sbrk来实现。
- 栈定位跳转:在C程序中使用goto只能在同一个函数内部跳转。setjmp/longjump用于在栈上定位和跳转,一般用于在多层嵌套函数中进行错误处理。注意事项:当使用longjmp跳转后,所到达栈的局部变量和寄存器变量的值是不确定的,它们可能回滚到setjmp之前的状态,因为编译器优化后,局部变量和寄存器变量可能位于CPU寄存器上。而位于内存上的静态变量和volatile变量则没有这个问题,它们都保持最近一次被修改的值。
- 系统资源限制:getrlimit/setrlimit用于获取设置进程的软硬资源限制,对应系统命令为ulimit
读书笔记-APUE第三版-(7)进程环境,布布扣,bubuko.com
时间: 2024-12-22 05:47:17