Linux内存分布

环境:Linux,redhat

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

各段的作用是:

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

为什么需要分段呢,这是有理由的,总的来说,第一点是为了将程序的层次划分清晰,不过这点似乎不是最重要的原因才说得过去;第二点,① 由编译器负责挑选出数据具备的属性,从而根据属性将程序片段分类,比如,划分出了只读属性的代码段和可写属性的数据段;② 由内核分配段的属性(例如读、写、执行等); ③ 这时候就可以将段描述符写进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;
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

ps aux 查看进程的进程号

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

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

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

时间: 2024-12-19 12:12:44

Linux内存分布的相关文章

linux下的内存分布

周日讲了32位linux下的内存分布 还有关于C语言中的extern和static的用法 内存的最高1G是用作系统保留,接下来是占空间,在靠近3G的那一块 再下来是堆空间,之后是bss区,未初始化的静态变量区 然后是Rw data区 Ro data区,主要用作存储字符串类型 接下来是代码段,又名txt正文段 0xffffffff 内核 0xbfff ffff 栈 堆 bss区 rw data ro data 代码段 0x00000000 接下来就是验证 1 #include <stdio.h>

linux内存管理

一.Linux 进程在内存中的数据结构 一个可执行程序在存储(没有调入内存)时分为代码段,数据段,未初始化数据段三部分:    1) 代码段:存放CPU执行的机器指令.通常代码区是共享的,即其它执行程序可调用它.假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段.     2) 数据段:存放已初始化的全局变量.静态变量(包括全局和局部的).常量.static全局变量和static函数只能在当前文件中被调用.     3) 未初始化数据区(uninitializeddata s

Linux内存管理 【转】

转自:http://blog.chinaunix.net/uid-25909619-id-4491368.html Linux内存管理 摘要:本章首先以应用程序开发者的角度审视Linux的进程内存管理,在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法.力求从外到内.水到渠成地引导网友分析Linux的内存管理与使用.在本章最后,我们给出一个内存映射的实例,帮助网友们理解内核内存管理与用户内存管理之间的关系,希望大家最终能驾驭Linux内存管理. 前言 内存管理一向是所有操作系统书

C++对象内存分布(2) - 菱形继承(non virtual)

1.前言 本篇文章的所有代码例子,如果是windows上编译运行,则使用的是visual studio 2013.如果是RHEL6.5平台(linux kernal: 2.6.32-431.el6.i686)上编译运行,则其gcc版本为4.4.7,如下所示: [[email protected] ~]# gcc --version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4) 2.菱形继承类的内存分布 2.1.类的结构 菱形继承 - 重复继承 2.2.实现

启动期间的内存管理之初始化过程概述----Linux内存管理(九)

日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDrivers Linux内存管理 在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检测到可用内存和寄存器. 而我们今天要讲的boot阶段就是系统初始化阶段使用的内存分配器. 1 前景回顾 1.1

Linux内核分析(三)----初识linux内存管理子系统

Linux内核分析(三) 昨天我们对内核模块进行了简单的分析,今天为了让我们今后的分析没有太多障碍,我们今天先简单的分析一下linux的内存管理子系统,linux的内存管理子系统相当的庞大,所以我们今天只是初识,只要对其进行简单的了解就好了,不会去追究代码,但是在后面我们还会对内存管理子系统进行一次深度的分析. 在分析今天的内容之前,我们先来看出自http://bbs.chinaunix.net/thread-2018659-2-1.html的一位大神做的内存管理图,真心佩服大神.其实这张图可以

Linux 内存池设计构想

一.基本数据结构 1 union m_block 2 { 3 union m_block* next; 4 unsigned int size; 5 }; 6 7 struct m_list 8 { 9 union m_block* free; 10 pthread_spinlock_t lock; 11 unsigned int size; 12 }; 13 14 struct m_pool 15 { 16 struct m_pool* next; 17 }; 18 19 struct m_m

Linux内存管理介绍

linux内存管理概述 内存管理的目标: 提供一种方法,在各种目的各个用户之间实现内存共享,应该实现以下两个功能: 1.最小化管理内存的时间,内存申请和释放响应时间短 2.最优化用于一般应用的可用内存,内存管理(算法)所占用的内存少,浪费的内存少(内存碎片少) 下图为内存分配器的关系: 1.kmalloc用于分配一块以字节数为单位的内存,所分配的内存物理地址是连续的 void *kmalloc(size_t size, gfp_t flags); size > SLUB_MAX_SIZE(2*P

windows和Linux内存的对齐方式

一.内存对齐的初步讲解 内存对齐可以用一句话来概括: "数据项只能存储在地址是数据项大小的整数倍的内存位置上" 例如int类型占用4个字节,地址只能在0,4,8等位置上. 例1: #include <stdio.h> struct xx{ char b; int a; int c; char d; }; int main() { struct xx bb; printf("&a = %p\n", &bb.a); printf("