[转]C程序内存区域分配(5个段作用)
http://www.360doc.com/content/11/0330/21/1317564_105977930.shtml
http://hi.baidu.com/bitcore/blog/item/77c521c65f4512d7d10060eb.html
http://apps.hi.baidu.com/share/detail/22734757
http://my.oschina.net/alphajay/blog/3870
一、C语言可执行代码结构
| 名称 | 内容 |
| 代码段 | 可执行代码、字符串常量 |
| 数据段 | 已初始化全局变量、已初始化全局静态变量、局部静态变量、常量数据 |
| BSS段 | 未初始化全局变量,未初始化全局静态变量 |
| 栈 | 局部变量、函数参数 |
| 堆 | 动态内存分配 |
一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务)在存储(没有调入到内存运行)时拥有3个部分,分别是代码段(text)、数据段(data)和BSS段。这3个部分一起组成了该可执行程序的文件。
(1)代码段(text segment):存放CPU执行的机器指令。通常代码段是可共享的,这使得需要频繁被执行的程序只需要在内存中拥有一份拷贝即可。代码段也通常是只读的,这样可以防止其他程序意外地修改其指令。另外,代码段还规划了局部数据所申请的内存空间信息。
代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
(2)数据段(data segment):或称全局初始化数据段/静态数据段(initialized data segment/data segment)。该段包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据。
(3)未初始化数据段:亦称BSS(Block Started by Symbol)。该段存入的是全局未初始化变量、静态未初始化变量。
而当程序被加载到内存单元时,则需要另外两个域:堆域和栈域。图1-1所示为可执行代码存储态和运行态的结构对照图。一个正在运行的C程序占用的内存区域分为代码段、初始化数据段、未初始化数据段(BSS)、堆、栈5个部分。

图1-1 C语言可执行代码结构
(4)栈段(stack):存放函数的参数值、局部变量的值,以及在进行任务切换时存放当前任务的上下文内容。
(5)堆段(heap):用于动态内存分配,即使用malloc/free系列函数来管理的内存空间。
在将应用程序加载到内存空间执行时,操作系统负责代码段、数据段和BSS段的加载,并将在内存中为这些段分配空间。栈段亦由操作系统分配和管理,而不需要程序员显示地管理;堆段由程序员自己管理,即显示地申请和释放空间。
另外,可执行程序在运行时具有相应的程序属性。在有操作系统支持时,这些属性页由操作系统管理和维护。
二、例子演示,代码段、数据段和BSS段存储变量类型
#include <stdio.h>
const int g_A = 10; //代码段
int g_B = 20; //数据段
static int g_C = 30; //数据段
static int g_D; //BSS段
int g_E; //BSS段
char *p1; //BSS段
void main( )
{
int local_A; //栈
static int local_C = 0; //数据段
static int local_D; //数据段
char *p3 = "123456"; //123456在代码段,p3在栈上
p1 = (char *)malloc( 10 ); //堆,分配得来得10字节的区域在堆区
strcpy( p1, "123456" ); //123456{post.content}放在常量区,编译器可能会将它与p3所指向 的"123456"优化成一块
printf("\n");
printf( "代码段,全局初始化变量, 只读const, g_A, addr:0x%08x\n", &g_A);
printf("\n");
printf( "数据段,全局变量, 初始化 g_B, addr:0x%08x\n", &g_B);
printf( "数据段,静态全局变量, 初始化, g_C, addr:0x%08x\n", &g_C);
printf("\n");
printf( "BSS段, 全局变量, 未初始化 g_E, addr:0x%08x\n", &g_E, g_E );
printf( "BSS段, 静态全局变量, 未初始化, g_D, addr:0x%08x\n", &g_D );
printf( "BSS段, 静态局部变量, 初始化, local_C, addr:0x%08x\n", &local_C);
printf( "BSS段, 静态局部变量, 未初始化, local_D, addr:0x%08x\n", &local_D);
printf("\n");
printf( "栈, 局部变量, local_A, addr:0x%08x\n", &local_A );
printf("\n");
printf( "堆, malloc分配内存, p1, addr:0x%08x\n", p1 );
}

注意:
编译时需要-g选项,这样才可以看elf信息;
readelf -a MemoryAssign > 1.txt
可执行程序MemoryAssign的信息导出到文本文件1.txt中,查看1.txt


问题1:可执行文件大小由什么决定?
可执行文件在存储时分为代码段、数据段和BSS段三个部分。
【例一】
程序1:
int ar[30000];
void main()
{
......
}
程序2:
int ar[300000] = {1, 2, 3, 4, 5, 6 };
void main()
{
......
}
发现程序2编译之后所得的.exe文件比程序1的要大得多。当下甚为不解,于是手工编译了一下,并使用了/FAs编译选项来查看了一下其各自的.asm,发现在程序1.asm中ar的定义如下:
_BSS SEGMENT
?ar@@3PAHA DD 0493e0H DUP (?) ; ar
_BSS ENDS
而在程序2.asm中,ar被定义为:
_DATA SEGMENT
?ar@@3PAHA DD 01H ; ar
DD 02H
DD 03H
ORG $+1199988
_DATA ENDS
区别很明显,一个位于.bss段,而另一个位于.data段,两者的区别在于:全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间。
.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化,因此造成了上述情况。

可以看到可执行文件“2”大小为122K,可执行文件“1”大小为4.8K,用size命令查看二进制可执行文件结构情况。
[转]C程序内存区域分配(5个段作用)的更多相关文章
- 程序或-内存区域分配& ELF分析 ***
一.在学习之前我们先看看ELF文件. ELF分为三种类型: 1. .o 可重定位文件(relocalble file) 2. 可执行文件 3. 共享库(shared library) 三种格式基本上从 ...
- 1 - JVM随笔分类(java虚拟机的内存区域分配(一个不断记录和推翻以及再记录的一个过程))
java虚拟机的内存区域分配 在JVM运行时,类加载器ClassLoader在加载到类的字节码后,交由jvm的执行引擎处理, 执行过程中需要空间来存储数据(类似于Cpu及主存),此时的这段空间的分 ...
- 深入C语言内存区域分配(进程的各个段)详解(转)
原文地址:http://www.jb51.net/article/39696.htm 一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务) ...
- C 语言内存区域分配(进程的各个段)详解
C语言可执行代码结构 名称 内容 代码段 可执行代码.字符串常量 数据段 已初始化全局变量.已初始化全局静态变量.局部静态变量.常量数据 BSS段 未初始化全局变量,未初始化全局静态变量 栈 ...
- [转]深入C语言内存区域分配(进程的各个段)详解
一般情况下,一个可执行二进制程序(更确切的说,在Linux操作系统下为一个进程单元,在UC/OSII中被称为任务)在存储(没有调入到内存运行)时拥有3个部分,分别是代码段(text).数据段(data ...
- 面试之四:JVM内存区域分配
1.程序计数器(线程私有)[不会OOM] 记录线程执行的代码位置,每个线程各自独有. 2.栈:虚拟机栈和本地方法栈(线程私有)[会OOM和StackOverflow] 虚拟机栈 每个JAVA方法在执行 ...
- Java内存区域分配基恩内存溢出异常
- C程序内存分配
在多任务操作系统中的每一个进程都运行在一个属于它自己的内存沙盘中.这个沙盘就是虚拟地址空间(virtual address space),在32位模式下它总是一个4GB的内存地址块.这些虚拟地址通过页 ...
- 学习jvm(一)--java内存区域
前言 通过学习深入理解java虚拟机的教程,以及自己在网上的查询的资料,做一个对jvm学习过程中的小总结. 本文章内容首先讲解java的内存分布区域,之后讲内存的分配原则以及内存的监控工具.再下来会着 ...
随机推荐
- Hibernate-一对多的关系维护
一对多 和多对一 一般是看需求来确定的,很多时候都是设置成双向的 举个最最普通的离子 :一个班级里面有多个学生 多个学生属于一个班级 从学生表来看 就是多对一的关系 从班级表来看就是一对多的关系 需求 ...
- druid(德鲁伊)数据源的使用和配置 阿里出品
pom.xml <dependency> <groupId>com.alibaba</groupId> <artifactId>drui ...
- 【Gym 100685J】Just Another Disney Problem(交互/排序)
第一次做交互题. 题意是有n个数(n<1000),你通过问1 a b,后台返回你YES代表a<b,NO代表a>b.要你在10000次询问内给出一个符合的排列.n=1000来说,100 ...
- 写在SDOI2016Round1前的To Do List
理性的整理了一下自己的不足. 计算几何啥都不会,字符串类DP毫无练习,数据结构写的不熟,数论推不出式子,网络流建模常建残: 需要达成的任务: 一.网络流: 熟练网络流的板子(之前一直仰慕zkw费用流, ...
- [NOIP1997] P2626 斐波那契数列(升级版)
题目背景 大家都知道,斐波那契数列是满足如下性质的一个数列: • f(1) = 1 • f(2) = 1 • f(n) = f(n-1) + f(n-2) (n ≥ 2 且 n 为整数). 题目描述 ...
- JBoss7.1配置外网访问
在JBoss7.1目录jboss-as-7.1.1.Final/standalone/configuration下找到standalone.xml,找到以下的节点,在尝试了以下两种方法: 1. < ...
- HTTPS 协议降级攻击原理
0x00 HTTPS 在传统流行的web服务中,由于http协议没有对数据包进行加密,导致http协议下的网络包是明文传输,所以只要攻击者拦截到http协议下的数据包,就能直接窥探这些网络包的数据. ...
- Mac上的终端(Terminal)启动缓慢
最近重装10.9系统,装完后,发现终端(Terminal)启动之前1秒都不用,现在却需要5-10秒,搜寻了下,发现是终端的统日志导致的问题,只需要执行下下面的命令,终端就又身轻如燕了! sudo rm ...
- 分享一段Java搞笑的代码注释
今天在群里看到有人分享了一段搞笑的注释代码,觉得挺好玩的,在这里收藏一下 // _ooOoo_ // o8888888o // 88" . "88 // (| -_- |) // ...
- nginx配置ssl双向验证 nginx https ssl证书配置
1.安装nginx 参考<nginx安装>:http://www.ttlsa.com/nginx/nginx-install-on-linux/ 如果你想在单IP/服务器上配置多个http ...