Linux进程的虚拟地址空间

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", 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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值