Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1838024
  • 博文数量: 184
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2388
  • 用 户 组: 普通用户
  • 注册时间: 2016-12-21 22:26
个人简介

90后空巢老码农

文章分类

全部博文(184)

文章存档

2021年(26)

2020年(56)

2019年(54)

2018年(47)

2017年(1)

我的朋友

分类: LINUX

2020-01-05 22:54:11

进程和程序

程序包含的信息
1. 二进制格式标识,现在大多是UNIX实现采用deELF格式
2. 机器语言指令
3. 程序入口地址(一般包含输入参数和环境变量)
4. 数据:程序文件包含的变量初始值和程序使用的字面常量
5. 符号表以及重定位表
6. 共享库和动态链接信息
7. 其他信息
从内核角度看,进程由用户内存空间和一系列内核数据结构组成,其中用户内存空间包含了程序代码以及代码所使用的变量,而内核数据结构则适用于维护进程状态信息。记录在内核数据结构中的信息包括许多与进程相关的标识号(ids), 虚拟内存表、打开文件描述符表、信号传递以及处理的有关信息、进程中源使用以及限制、当前工作目录和其他信息


点击(此处)折叠或打开

  1. #include <unistd.h>
  2. pid_t getpid(void);
  3. /*always successfully returns process ID of caller*/
  4. pid_t getppid(void);
  5. /*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参数非常类似

点击(此处)折叠或打开

  1. #include <stdlib.h>
  2. char *getenv(const char *name);
  3. /*returns pointer to (value) string, or NULL if no such variable*/
  4. int putenv(char *string);
  5. /*returns 0 on success, or nonzero on error*/
string指向name=value形式的字符串,调用之后,该字符串就称为环境变量的一部分,换言之,environ变量中某一元素的指向与string参数的指向位置相同,而非string参数所指向字符串的赋值副本

点击(此处)折叠或打开

  1. #include <stdlib.h>
  2. int setenv(const char *name, const char *value, int overwrite);
  3. /*returns 0 on success, or -1 on error*/
  4. int unsetenv(const char *name);
  5. /*returns 0 on success, or -1 on error*/
setenv()函数为形如name=value的字符串分配一块内存缓冲区,并将name和value所指向的字符串复制到次缓冲区,overwrite为0或者非0表示当name存在时,是否覆盖


点击(此处)折叠或打开

  1. #define _BSD_SOURCE /*or: #define _SVID_SOURCE*/
  2. #include <stdlib.h>
  3. int clearenv(void);
  4. /*returns 0 on success, or a nonzero on error*/
该函数只是将指针environ置位NULL,所以它和setenv一起使用有可能会导致内存泄漏

非局部跳转


点击(此处)折叠或打开

  1. #include <setjmp.h>
  2. int setjmp(jmp_buf, env);
  3. /*returns 0 on initial call, nonzero on return via longjmp()*/
  4. void longjmp(jmp_buf env, int val);
很像try...catch...的底层实现

阅读(1160) | 评论(0) | 转发(0) |
0

上一篇:Linux文件I/O进阶

下一篇:Linux当中内存分配

给主人留下些什么吧!~~