Linux内存分布

环境:Linux,redhat

当一段程序被编译成为一个可执行的文件时,这个时候它已经被划分成代码段、数据段、栈段、.bss段、堆等部分。

各段的作用是:

1.代码段(.text):代码,全局常量(const),只读变量和字符串常量(有可能在代码段,一般被放在只读数据".rodata"段,还有可能就在“.data”段)
2.数据段(.data):全局变量(初始化以及未初始化的)、静态变量(全局的和局部的、初始化的以及未初始化的)。数据段包括初始化的数据和未初始化的数据(BSS)两部分。BSS段存放的是未初始化的全局变量和静态变量。BSS段在不占可执行文件空间,文件只记录BSS段的在内存中的开始和结束地址。
3.堆:动态分配的区域。
4.栈:局部变量(初始化以及未初始化的,但不包含静态变量)、局部只读变量(const)。

SNAGHTMLeae3fc

为什么需要分段呢,这是有理由的,总的来说,第一点是为了将程序的层次划分清晰,不过这点似乎不是最重要的原因才说得过去;第二点,① 由编译器负责挑选出数据具备的属性,从而根据属性将程序片段分类,比如,划分出了只读属性的代码段和可写属性的数据段;② 由内核分配段的属性(例如读、写、执行等); ③ 这时候就可以将段描述符写进CPU的段寄存器中了,这就相当于操作系统定义段,然后要告知CPU,操作系统对段做了些什么,好让CPU做出相应的准备(例如只读段,CPU就不能去写,写操作就会产生异常)。

具体的讲解在我转载的这篇文章中已经说的很是详细了。http://my.oschina.net/yuyounglife/blog/706376

这里我拿几段重要的话出来。

做过开发的同学都清楚,尽量把同一属性的数据放在一起,这样易于维护。这一点类似于MVC,在程序逻辑中把模型、视图、控制这三部分分开,这样更新各部分时,不会影响到其他模块。

将数据和代码分开的好处有三点。

第一,可以为它们赋予不同的属性。

例如数据本身是需要修改的,所以数据就需要有可写的属性,不让数据段可写,那程序根本就无法执行啦。程序中的代码是不能被更改的,这样就要求代码段具备只读的属性。真要是在运行过程中程序的下一条指令被修改了,谁知道会产生什么样的灾难。

第二,为了提高CPU内部缓存的命中率。

大伙儿知道,缓存起作用的原因是程序的局部性原理。在CPU内部也有缓存机制,将程序中的指令和数据分离,这有利于增强程序的局部性。CPU内部有针对数据和针对指令的两种缓存机制,因此,将数据和代码分开存储将使程序运行得更快。

第三,节省内存。

程序中存在一些只读的部分,比如代码,当一个程序的多个副本同时运行时(比如同时执行多个ls命令时),没必要在内存中同时存在多个相同的代码段,这将浪费有限的物理内存资源,只要把这一个代码段共享就可以了。

/* 国嵌代码addr.c */

#include<stdio.h>
#include<stdlib.h>
int global_init_a = 0; // 全局 初始化的变量 数据段
int global_uninit_a;   // 全局 未初始化 BSS段
static int static_global_init_a = 1; // 全局 静态 初始化 数据段
static int static_global_uninit_a;   // 全局 静态 未初始化 BSS段
const int const_global_a=1;          // 全局 常量 代码段
 
int global_init_b = 0; // 全局 初始化 数据段
int global_uninit_b;   // 全局 未初始化 BSS段
static int static_global_init_b = 1; // 全局 静态 初始化 数据段
static int static_global_uninit_b;   // 全局 静态 未初始化 BSS段
const int const_global_b=1;          // 全局 常量 代码段
 
int main()
{
int local_init_a = 1;  // 局部 初始化 栈
int local_uninit_a;    // 局部 未初始化 栈 
static int static_local_init_a = 1; // 局部 静态 初始化 数据段
static int static_local_uninit_a;   // 局部 静态 未初始化 BSS段
const int const_local_a = 1;   // 局部 常量 栈
 
 
int local_init_b = 1; // 局部 初始化 栈
int local_uninit_b;   // 局部 未初始化 栈
static int static_local_init_b = 1; // 局部 静态 初始化 数据段
static int static_local_uninit_b;   // 局部 静态 未初始化 BSS段
const int const_local_b = 1; // 局部 常量 栈
 
int * malloc_p_a;  // malloc分配得到的局部 堆
malloc_p_a = malloc(sizeof(int));
 
printf("&global_init_a=%p, global_init_a=%d\n", &global_init_a, global_init_a);
printf("&global_uninit_a=%p, global_uninit_a=%d\n", &global_uninit_a, global_uninit_a);
printf("&static_global_init_a=%p, static_global_init_a=%d\n", &static_global_init_a, static_global_init_a);
printf("&static_global_uninit_a=%p, static_global_uninit_a=%d\n", &static_global_uninit_a, static_global_uninit_a);
printf("&const_global_a=%p, const_global_a=%d\n", &const_global_a, const_global_a);
 
printf("&global_init_b=%p, global_init_b=%d\n", &global_init_b, global_init_b);
printf("&global_uninit_b=%p, global_uninit_b=%d\n", &global_uninit_b, global_uninit_b);
printf("&static_global_init_b=%p, static_global_init_b=%d\n", &static_global_init_b, static_global_init_b);
printf("&static_global_uninit_b=%p, static_global_uninit_b=%d\n", &static_global_uninit_b, static_global_uninit_b);
printf("&const_global_b=%p, const_global_b=%d\n", &const_global_b, const_global_b);
 
printf("&local_init_a=%p, local_init_a=%d\n", &local_init_a, local_init_a);
printf("&local_uninit_a=%p, local_uninit_a=%d\n", &local_uninit_a, local_uninit_a);
printf("&static_local_init_a=%p, static_local_init_a=%d\n", &static_local_init_a, static_local_init_a);
printf("&static_local_uninit_a=%p, static_local_uninit_a=%d\n", &static_local_uninit_a, static_local_uninit_a);
printf("&const_local_a=%p, const_local_a=%d\n", &const_local_a, const_local_a);
 
printf("&local_init_b=%p, local_init_b=%d\n", &local_init_b, local_init_b);
printf("&local_uninit_b=%p, local_uninit_b=%d\n", &local_uninit_b, local_uninit_b);
printf("&static_local_init_b=%p, static_local_init_b=%d\n", &static_local_init_b, static_local_init_b);
printf("&static_local_uninit_b=%p, static_local_uninit_b=%d\n", &static_local_uninit_b, static_local_uninit_b);
printf("&const_local_b=%p, const_local_b=%d\n", &const_local_b, const_local_b);
 
printf("&malloc_p_a=%p, *malloc_p_a=%d\n", malloc_p_a, *malloc_p_a);
printf("&global_init_a=%p, global_init_a=%d\n", &global_init_a, global_init_a);
 
while(1)
;
 
return 0;
}
 
 
 
 
 
 
 
 
 
 
 
 

 

 

编译程序,gcc addr.c –o addr     然后运行程序   ./addr

ps aux 查看进程的进程号

cat /proc/6882(进程号)/maps   查看各段地址, 查看更为详细的地址readelf –S addr

对照着段的信息和程序打印出来的地址即可查到各个变量所在段。

这篇文章讲得也不错。http://www.jianshu.com/p/9f981f6433d1

转载于:https://my.oschina.net/yuyounglife/blog/706433

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值