您的位置:首页 > 运维架构 > Linux

Linux进程的虚拟地址空间

2015-07-20 11:24 696 查看
1.以32位系统为例,Linux系统中每个进程共有3GB的用户地址空间,当用户调用系统调用时,内核线程会代表进程运行,此时是在内核空间内运行的,故所有进程共享1GB的内核空间. 所以,总的来说,每个进程可用的地址空间共有4GB

2.进程的3GB用户地址空间由下图所示:



可以看出,进程的用户地址空间从0x00000000--0xbfffffff(2^30+2^31),依次是代码段,数据段,堆,堆栈


3.地址映射:

一个程序在经过编译、连接之后形成的地址空间是一个虚拟的地址空间,只有当程序运行的时候才会分配具体的物理空间.由此我们可以得知,程序的虚拟地址相对来说是固定的,而物理地址则随着每一次程序的运行而有所不同.

对于内核空间而言,它与物理内存之间存在一个简单的线性关系,即存在3GB的偏移量.在Linux内核中,这个偏移量叫做PAGE_OFFSET.如果内核的某个物理地址为x,那么对应的内核虚地址就为x+PAGE_OFFSET.

对于用户空间而言,它与物理内存之间的映射远不止这么简单.与内核空间和物理空间的线性映射不同的是,分页机制将虚拟用户空间和物理地址空间分成大小相同的页,然后再通过页表将虚拟页和物理页块映射起来.

4.虚拟地址空间举例:

用户地址空间:

#include <stdio.h>

int data_var = 0;
int bss_var;

int main(int argc, char *argv[])
{
static int static_data_var = 0;
static int static_bss_var, static_bss_var2, static_bss_var3;

int *malloc_var = malloc(sizeof(int));

int stack_data_var = 0;
int stack_bss_var;

printf("address main function: %p\n", main);

printf("address data: %p\n", &data_var);
printf("address bss: %p\n", &bss_var);

printf("address static data: %p\n", &static_data_var);
printf("address static bass data: %p\n", &static_bss_var);
printf("address static bass data2: %p\n", &static_bss_var2);
printf("address static bass data3: %p\n", &static_bss_var3);

printf("address malloc: %p\n", malloc_var);

printf("address stack data: %p\n", &stack_data_var);
printf("address stack bss data: %p\n", &stack_bss_var);

return 0;
}

运行结果:
address main function: 0x804844d
address data: 0x804a028
address bss: 0x804a03c
address static data: 0x804a02c
address static bass data: 0x804a030
address static bass data2: 0x804a034
address static bass data3: 0x804a038
address malloc: 0x99b9008
address stack data: 0xbfc17104
address stack bss data: 0xbfc17108

运行结果表明:

数据段中保存的是:已经初始化了的全局变量, static静态变量(不管是已经显示初始化了的还是没有初始化的)

bss段中保存的是:没有初始化的全局变量

堆中保存的是:类似malloc这样的函数申请时的动态变量

堆栈中保存的是:函数内部定义的变量(不管是已经初始化了的还是没有初始化的)


内核地址空间:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>

//必选
//模块许可声明
MODULE_LICENSE("GPL");
//模块加载函数

static int mm_init(void)
{

void *getpage_addrres, *kmalloc_address, *vmalloc_address;

getpage_addrres = __get_free_page(GFP_KERNEL);

kmalloc_address = kmalloc(sizeof(int), GFP_KERNEL);

vmalloc_address = vmalloc(sizeof(int));

printk("address get_page: %p\n", getpage_addrres);

printk("address kmalloc: %p\n", kmalloc_address);

printk("address vmalloc: %p\n
4000
", vmalloc_address);

printk(KERN_ALERT "mm_init success\n");

return 0;
}
//模块卸载函数
static void mm_exit(void)
{
printk(KERN_ALERT "mm_exit success\n");
}
//模块注册
module_init(mm_init);
module_exit(mm_exit);
//可选
MODULE_AUTHOR("edsionte Wu");
MODULE_DESCRIPTION("This is a simple example!\n");
MODULE_ALIAS("A simplest example");

运行结果:
address get_page: e1291000
address kmalloc: e11f8780
address vmalloc: f8430000

结果表明:

内核空间的地址都是大于0xc0000000的,也即从(2^31+2^30)开始


本文引述自:http://edsionte.com/techblog/archives/1922
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  虚拟地址