进程的虚拟地址空间
转载:http://edsionte.com/techblog/archives/1922
1.内核空间
一般可以通过__get_free_page()
、kmalloc()
和vmalloc()
来申请内核空间。只不过__get_free_page
函数每次申请的都是完整的页;而后两者则依据具体参数申请以字节为单位的内存空间。此外,前两个函数申请的虚拟地址空间和物理地址空间都是连续的;vmalloc函数申请的物理地址空间并不连续。vmalloc函数通过重新建立虚拟地址空间和物理地址空间之间的映射,即新建页表项,将离散的物理地址空间映射到连续的虚拟地址空间。因此,使用该函数的开销比较大。
下面的程序简单的演示了这三个函数的使用方法。从结果中可以看出,这些函数申请的地址都在3GB(0xBFFFFFFF)以上。
static int __init mmshow_init(void)
{
printk("mmshow module is working
");
pagemem = __get_free_page(GFP_KERNEL);
if(!pagemem)
goto gfp_fail;
printk(KERN_INFO "pagemem = 0x%lx
",pagemem);
kmallocmem = kmalloc(100 * sizeof(char),GFP_KERNEL);
if(!kmallocmem)
goto kmalloc_fail;
printk(KERN_INFO "kmallocmem = 0x%p
",kmallocmem);
vmallocmem = vmalloc(1000000 * sizeof(char));
if(!vmallocmem)
goto vmalloc_fail;
printk(KERN_INFO "vmallocmem = 0x%p
",vmallocmem);
return 0;
gfp_fail:
free_page(pagemem);
kmalloc_fail:
kfree(kmallocmem);
vmalloc_fail:
vfree(vmallocmem);
return -1;
}
//运行结果:
[ 5542.073900] mmshow module is working
[ 5542.073904] pagemem = 0xf3211000
[ 5542.073907] kmallocmem = 0xd581e700
[ 5542.073983] vmallocmem = 0xf9251000
2.用户空间
如前所述,每个进程够拥有属于自己的3GB的虚拟空间,那么这个3GB的空间是如何划分的?通常,除了我们熟悉的代码段和数据段,用户空间还包括堆栈段和堆。我们可以通过下面的演示程序来了解这些区域到底负责存储程序的那些内容。
int bss_var;
int data_var0 = 1;
int main(int argc,char **argv)
{
printf("The user space's address division of a process as follow:
");
printf("Data segment:
");
printf("address of "main" function:%p
",main);
printf("Data segment:
");
printf("address of data_var:%p
",&data_var0);
static int data_var1 = 4;
printf("new end of data_var:%p
",&data_var1);
printf("BSS:
");
printf("address of bss_var:%p
",&bss_var);
char *str = (char *)malloc(sizeof(char)*10);
printf("initial heap end:%p
",str);
char *buf = (char *)malloc(sizeof(char)*10);
printf("new heap end:%p
",buf);
int stack_var0 = 2;
printf("Stack segment:
");
printf("initial end of stack:%p
",&stack_var0);
int stack_var1 = 3;
printf("new end of stack:%p
",&stack_var1);
return 0;
}
//运行结果:
The user space's address division of a process as follow:
Data segment:
address of "main" function:0x8048454
Data segment:
address of data_var:0x804a01c
new end of data_var:0x804a020
BSS:
address of bss_var:0x804a02c
initial heap end:0x8f77008
new heap end:0x8f77018
Stack segment:
initial end of stack:0xbfe0a3b4
new end of stack:0xbfe0a3b0
可以看到,代码段存放程序的代码;数据段存放全局变量和static类型的局部变量。此外,未初始化的全局变量虽然也存在于数据段,但是这些未初始化的变量都集中在靠近数据段上边界的区域,这个区域称为BSS段。以上这些空间是进程所必须拥有的,它们在进程运行之前就分配好了。
程序中的局部变量一般被分配在堆栈段,其位于用户空间最顶部。与固定的代码段和数据段不同的是,堆栈段存储数据是从高低值往低地址延伸的。因此,在数据段到堆栈段之间,形成了一片空洞,这片空洞用于存储malloc函数所动态分配的空间,这片空洞区域被称为堆。
通过下面这个图可以更进一步的了解到进程用户空间的划分情况。