64位系统下进程的内存布局

环境

  1. 操作系统:ubuntu15.04
  2. 物理内存:4G

测试程序


#include<stdio.h>
#include<stdlib.h>

int  a;
int  b=1;

main()
{
    int  n = 0;
    char *p1 = NULL;
    char *p2 = NULL;
    const int s = 10;
    p1 = (char*)malloc(200);
    p2 = "hello";

    printf("main  %p\n",main);
    printf("未初始化 a   %p\n",&a);
    printf("初始化   b   %p\n",&b);
    printf("局部变量 n   %p\n",&n);
    printf("动态内存 p1  %p\n",p1);
    printf("常量     s   %p\n",&s);
    printf("常字符串 p2  %p\n",p2);

    while(1)
    {}
}

查看内存地址空间方式

以下2种方式可以结合着观察

1、 pmap 命令

pmap [参数] [进程pid]

参数:

  • -d 显示详细设备信息
  • -q 不显示首尾行信息

运行测试程序,用top或ps 命令查询进程pid:

这里写图片描述


属性 含义
Address 地址空间:起始地址~
Kbytes 大小
Mode 权限:r可读、w可写、x可执行、s共享内存、p私有内存
Offset 虚拟内存偏移量
Device 所在设备(主:次): 008:00008表示sda8
mapped 虚拟内存分配大小
shared 共享内存大小

mem 是运行程序的名字
.so 是使用的动态链接库
stack 使用的栈空间
anon 预分配的虚拟内存,还未有数据占用


2、查看 /proc/pid号/maps 文件内容

这里写图片描述

这个要比上面显示的更详细一点

每一行依次对应的是:
地址范围、权限、偏移量、设备、文件inode、映射对象

第1行 [可读可执行] 是程序的文本段
第2行 [只读]………….不清楚
第3行 [可读可写] 是程序的数据段(包括初始化数据段和未初始化数据段)
第4行 ………………..堆空间
第16行 ………………栈空间

vdso 和 vsyscall ……………系统的快速调用
http://blog.csdn.net/maimang1001/article/details/17331731

用 ls -i 可查看源文件的inode,符合第5列;链接库在根分区下,我的是sda8,源程序在home下,我的是sda8,符合第4列。

3、程序的运行结果

这里写图片描述

从程序的入口地址main 0x400586 可以看出,maps文件的第一行确实是程序的代码段。

全局变量(初始化和未初始化)位于数据段,对应第3行

局部变量位于栈段

const 常量位于栈段

常字符串位于文本段

动态申请内存位于堆段


64位系统中应该有48根地址总线,低位:0~47位才是有效的可变地址,高位:48~63位全补0或全补1。一般高位全补0对应的地址空间是用户态,如上面的第1~18行。高位全补1对应的是内核态,如上面的第19行。这64位的地址空间并不能全部被使用(太多了),所以用户态和内核态之间会有未使用的空间(据说叫AMD64空洞)。

由上图的文件内容可以看出,从低地址到高地址内存布局依次是:

保留区 –> 文本段–>数据段—>堆—>共享库—>栈–>环境变量—>内核态

由pmap 命令和maps的显示可看出,栈和堆的中间部分是共享库,栈空间地址减小向下增长,堆空间地址增大向上增长。我觉得堆栈增长的时候,数据会先往紧挨的已分配内存anon中放,anon不够用时再继续增长,新分配内存。


这里写图片描述

dmesg 命令

显示系统启动时的信息

dmesg链接

猜你喜欢

转载自blog.csdn.net/lyh__521/article/details/50137057