进程概述和内存分配
本文是作者阅读TLPI(The Linux Programer Interface的总结),为了突出重点,避免一刀砍,我不会过多的去介绍基本的概念和用法,我重点会去介绍原理和细节。因此对于本文的读者,至少要求读过APUE,或者是实际有写过相关代码的程序员,因为知识有点零散,所以我会尽可能以FAQ的形式呈现给读者。
进程
一个进程的内存布局是什么样的?
每个进程所所分配的内存由很多部分组成,通常我们称之为段,一般会有如下段:
- 文本段 包含了进程执行的程序机器语言指令,文本段具有只读属性,以防止进程通过错误指针意外修改自身的指令。
- 初始化数据段包含了显示初始化的全局变量和静态变量,当程序加载到内存时,从可执行文件中读取这些变量的值
- 未初始化数据段包含了未进行显式初始化的全局变量和静态变量,程序启动之前,系统将本段内所有的内存初始化为0。
- 栈段是一个动态增长和收缩的段,由栈帧组成,系统会为每个当前调用的函数分配一个栈帧,栈帧中存储了函数的具备变量,实参,和返回值。
- 堆段是可在运行时动态进程内存分配的一块区域,堆顶端称作program break
注: 为什么要区分初始化数据段,和未初始化数据段呢?,未初始化数据段简称为BSS段,有何含义BSS全称为Block Started by Symbol,其主要原因在于程序在磁盘上存储时,没有必要为未经初始化的变量分配存储空间,相反,可执行文件只需要记录未初始化数据段的位置和所需大小即可。直到运行时才分配内存空间。通过size命令可以显示可执行文件的文本段,初始化数据段,未初始化数据段的段大小信息。
如何知道进程的文本段,初始化数据段和非初始化数据段的结束位置?
大多数UNIX实现中C语言编程环境提供了三个全局符号:etext,edata,end,可在程序内使用这些符号获取文本段,初始化数据段,未初始化数据段结尾处下一字节的地址。代码如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
extern char etext,edata,end;
int main()
{
printf("%p\n",&etext);
printf("%p\n",&edata);
printf("%p\n",&end);
}
如何获取虚拟内存的页面大小?
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("page-size:%d\n",sysconf(_SC_PAGESIZE));
}
如何读取任一进程的命令行参数和程序名?
通过读取proc/PID/cmdline
可以得到任一进程的命令行参数信息,如果想获取程序本身的命令行参数,可以使用proc/self/cmdline
来读取,对于如何获取进程的程序名有如下两种方法:
- 读取
/proc/self/exe
的符号链接内容,这个文件会通过符号链接到真正的可执行文件路径,是绝对路径,通过readlink可以读取其中链接的绝对路径名称
#include <stdio.h>
#include <unistd.h>
#include <string.h>
char * get_program_path(char *buf,int count);
char * get_program_name(char *buf,int count);
int main()
{
//程序测试
char buf[1024];
bzero(buf,sizeof(buf));
//打印路径名称
printf("%s\n",get_program_path(buf,sizeof(buf)));
bzero(buf,sizeof(buf));
//打印程序名称
printf("%s\n",get_program_name(buf,sizeof(buf)));
}
/*
* 获取程序的路径名称
*/
char * get_program_path(char *buf,int count)
{
int i=0;
int retval = readlink("/proc/self/exe",buf,count-1);
if((retval < 0 || retval >= count - 1))
{
return NULL;
}
//添加末尾结束符号
buf[retval] = '\0';
char *end = strrchr(buf,'/');
if(NULL == end)
buf[0] = '\0';
else
*end = '\0';
return buf;
}
/*
* 获取这个程序的文件名,其实这有点多余,argv[0]
* 就代表这个执行的程序文件名
*/
char * get_program_name(char *buf,int count)
{
int retval = readlink("/proc/self/exe",buf,count-