文档章节

Linux内存分布

小师life
 小师life
发布于 2016/07/05 15:58
字数 1447
阅读 16
收藏 0

环境: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

© 著作权归作者所有

小师life
粉丝 0
博文 32
码字总数 6965
作品 0
武汉
程序员
私信 提问
NUMA架构的CPU -- 你真的用好了么?

NUMA架构的CPU -- 你真的用好了么? 本文从NUMA的介绍引出常见的NUMA使用中的陷阱,继而讨论对于NUMA系统的优化方法和一些值得关注的方向。 文章欢迎转载,但转载时请保留本段文字,并置于文...

天天顺利
2015/05/15
81
0
剖析Linux系统下基于NUMA构建的服务器

NUMA(Non-Uniform Memory Access Architecture)系统在市场上的应用越来越广泛,许多厂商都成功推出了基于 NUMA 架构的服务器,本文重点讨论了当前 Linux 的 NUMA 技术,主要包括:存储管理、N...

zt371
2009/05/07
467
0
Facebook 开源 oomd,一种处理内存溢出的新方法

文章来自开源中国(微信ID:oschina2013) 责编:局长 如需转载请注明上述来源,其他来源无效并视为侵权 近日,在 Facebook 的网站上,该公司的开发者 Daniel Xu 宣布在 GPLv2 许可证下开源o...

开源中国
2018/07/23
0
0
Facebook 开源内存溢出杀手 oomd

导读 近日,在 Facebook 的网站上,该公司的 Daniel Xu 宣布在 GPLv2 许可证下开源 oomd。oomd 是用户空间内存溢出杀手(OOM Killer),它在最近关于块 I/O 延迟控制器的文章中有被提及到。当内...

问题终结者
2018/07/30
18
0
Facebook 开源 oomd,一种处理内存溢出的新方法

近日,在 Facebook 的网站上,该公司的开发者 Daniel Xu 宣布在 GPLv2 许可证下开源 oomd。oomd 是用户空间内存溢出杀手(OOM Killer),它在最近关于块 I/O 延迟控制器的文章中有被提及到。当...

局长
2018/07/23
3.9K
3

没有更多内容

加载失败,请刷新页面

加载更多

iOS苹果应用IPA一键签名工具及重签教程

开心签名工具,是一款跨平台ios签名和重签名工具。 同时支持在windows、linux、mac运行,数据同步,方便使用及管理! 开心重签名工具官网 功能特点 1、支持图形界面及命令行重签(部署到服务...

tintong
23分钟前
3
0
2.4G有源卡核心芯片供应商

有源2.4G RFID的防盗标签,在与无源标签相比较,通信距离远,通信时效高。我司的SI24R2E这颗芯片专门为2.4G有源标签而设计,具有低功耗,发送距离远,厂商设计简单等优势;广泛应用于现在城市...

文刀石
29分钟前
2
0
设置Ubuntu16.04启动为命令行界面

1. 修改/etc/default/grub文件,将GRUB_CMDLINE_LINUX_DEFAULT设置成”quiet splash 3” 2. 使用命令update-grub使得在/boot下重新生成GRUB2配置文件。 3. 重启...

JosiahMg
29分钟前
3
0
C++基础知识点

计算机语言 计算机不能理解高级语言,只能理解机器语言,必须要将高级语言翻译成机器语言,翻译的方式有两种,一种是编译,一种是解释 解释型语言,在运行程序时进行翻译,每个语句在执行时逐...

大瑞清_liurq
36分钟前
3
0
EFCore 多条数据更新不能同时savechanges()的解决方法

1 在ModelContext定义下增加var transaction = ctx.Database.BeginTransaction(); 1.2 在最后一个SaveChanges()后增加transaction.Commit(); 3 在finally的if (sMsgCode != "")分支中增加tra......

_Somuns
39分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部