进程和程序
程序包含的信息
1. 二进制格式标识,现在大多是UNIX实现采用deELF格式
2. 机器语言指令
3. 程序入口地址(一般包含输入参数和环境变量)
4. 数据:程序文件包含的变量初始值和程序使用的字面常量
5. 符号表以及重定位表
6. 共享库和动态链接信息
7. 其他信息
从内核角度看,进程由用户内存空间和一系列内核数据结构组成,其中用户内存空间包含了程序代码以及代码所使用的变量,而内核数据结构则适用于维护进程状态信息。记录在内核数据结构中的信息包括许多与进程相关的标识号(ids), 虚拟内存表、打开文件描述符表、信号传递以及处理的有关信息、进程中源使用以及限制、当前工作目录和其他信息
-
#include <unistd.h>
-
pid_t getpid(void);
-
/*always successfully returns process ID of caller*/
-
pid_t getppid(void);
-
/*always successfully returns process ID of parent of caller*/
进程内存布局
每个进程所分配的内存由很多部分组成,通常称之为段(segment)
1. 文本段包含进程运行的机器语言指令,只读,可共享
2. 初始化数据段包含显式初始化的全局变量和静态变量。
3. 未初始化数据段(BSS段),包含了未进行显式初始化的
全局变量和静态变量。程序启动之前,系统将本段内所有内存初始化为0
4. 栈,是一个动态增长和收缩的段,由栈帧组成
5. 堆,是可在运行时动态进行内存分配的一块区域
虚拟内存空间
空间局部性(spatial locality):程序倾向于访问在最近访问过的内存地址附近的内存
时间局部性(Temporal locality):程序倾向于在不久的将来再次访问最近刚刚访问过的内存地址
正是由于上述两种特性,使得程序即便仅有部分地址空间位于RAM当中,依然可能得以执行
程序当中在内存中驻留的页叫
驻留集(resident set),未使用的页拷贝保存在交换区(swap area)——磁盘中的保留区域,作为计算机RAM的补充
在进程虚拟地址空间中,并非所有的地址范围都需要页表条目
由于内核能够为进程分配和释放页(和页表条目),所以进程的有效虚拟地址范围在其声明周期中可以发生变化。可能场景如下:
1. 栈向下增长时超出之前曾达到的位置
2. 堆中分配或释放内存时,通过调用brk(), sbrk(), malloc()...来提升program break的位置
3. 共享内存时(shmat(), shmdt(), mmap(), munmap())
每个(用户)栈帧包括如下信息:
1. 函数实参和局部变量
2. 调用的链接信息,每当一个函数调用另一个函数时,会在被调用函数的栈帧中保存一些寄存器的副本,以便返回时恢复
环境列表
在c语言程序中,可以使用全局变量char **environ访问环境列表(C运行时启动代码定义了该变量并以环境列表位置为其赋值),environ和argv参数非常类似
-
#include <stdlib.h>
-
char *getenv(const char *name);
-
/*returns pointer to (value) string, or NULL if no such variable*/
-
int putenv(char *string);
-
/*returns 0 on success, or nonzero on error*/
string指向name=value形式的字符串,调用之后,该字符串就称为环境变量的一部分,换言之,environ变量中某一元素的指向与string参数的指向位置相同,而非string参数所指向字符串的赋值副本
-
#include <stdlib.h>
-
int setenv(const char *name, const char *value, int overwrite);
-
/*returns 0 on success, or -1 on error*/
-
int unsetenv(const char *name);
-
/*returns 0 on success, or -1 on error*/
setenv()函数为形如name=value的字符串分配一块内存缓冲区,并将name和value所指向的字符串复制到次缓冲区,overwrite为0或者非0表示当name存在时,是否覆盖
-
#define _BSD_SOURCE /*or: #define _SVID_SOURCE*/
-
#include <stdlib.h>
-
int clearenv(void);
-
/*returns 0 on success, or a nonzero on error*/
该函数只是将指针environ置位NULL,所以它和setenv一起使用有
可能会导致内存泄漏
非局部跳转
-
#include <setjmp.h>
-
int setjmp(jmp_buf, env);
-
/*returns 0 on initial call, nonzero on return via longjmp()*/
-
void longjmp(jmp_buf env, int val);
很像try...catch...的底层实现
阅读(1222) | 评论(0) | 转发(0) |