在解释bss段与data段区别前,先来看下他们定义,以及内存中的位置。

虚拟地址空间

在32位x86的Linux系统中,虚拟地址空间布局如下图所示:

虚拟地址空间分布

bss段(bss segment):bss是Block Started by Symbol的简称,用来存放程序中未初始化的全局变量的内存区域,属于静态内存分配。

data段(data segment):用来存放程序中已初始化的全局变量的内存区域,属于静态内存分配。

text段(text segment):用来存放程序执行代码的内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读(某些架构也允许代码段为可写,即允许修改程序)。也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。

栈(stack):用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在data段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。

上面只是简单介绍了各个内存段,如果想详细了解,可以看这篇文章《深度解析内存中的程序》。

bss段与data段的区别

在初始化时 bss 段部分将会清零。bss 段属于静态内存分配,即程序一开始就将其清零了。

比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。

text 和 data 段都在可执行文件中,由系统从可执行文件中加载;

而 bss 段不在可执行文件中,由系统初始化。

上面这些理论可能有些抽象,下面我们通过示例代码来对比两者区别。

示例代码

#include

int bss_1;// 未初始化的全局变量,bss段

int bss_2 = 0;// 初始化为0的全局变量,bss段

int data_1 = 1;// 初始化非0的全局变量,data段

int main() {

static int bss_3;// 未初始化的静态局部变量,bss段

static int bss_4 = 0;// 初始化为0静态局部变量,bss段

static int data_2 = 1;// 初始化非0静态局部变量,data段

printf("bss段地址:bss_1 = %p\n", &bss_1);

printf("bss段地址:bss_2 = %p\n", &bss_2);

printf("bss段地址:bss_3 = %p\n", &bss_3);

printf("bss段地址:bss_4 = %p\n\n", &bss_4);

printf("data段地址:data_1 = %p\n", &data_1);

printf("data段地址:data_2 = %p\n", &data_2);

return 0;

}

使用 objdump -t 反汇编查看变量的存储位置。

gcc bss_data_test.c -o bss_data_test

objdump -t bss_data_test | grep bss_

bss_data_test: 文件格式 elf64-x86-64

0000000000000000 l df *ABS* 0000000000000000 bss_data_test.c

0000000000601048 l O .bss 0000000000000004 bss_3.2288

000000000060104c l O .bss 0000000000000004 bss_4.2289

0000000000601044 g O .bss 0000000000000004 bss_2

0000000000601040 g .bss 0000000000000000 __bss_start

0000000000601050 g O .bss 0000000000000004 bss_1

objdump -t bss_data_test | grep data_

bss_data_test: 文件格式 elf64-x86-64

0000000000000000 l df *ABS* 0000000000000000 bss_data_test.c

000000000060103c l O .data 0000000000000004 data_2.2290

0000000000601028 w .data 0000000000000000 data_start

0000000000601038 g O .data 0000000000000004 data_1

0000000000601028 g .data 0000000000000000 __data_start

可以看到,变量所处位置与代码中注释的一致。

我们再运行起来, 看一下地址,确实是data段位于bss段的下方:

./bss_data_test

bss段地址:bss_1 = 0x601050

bss段地址:bss_2 = 0x601044

bss段地址:bss_3 = 0x601048

bss段地址:bss_4 = 0x60104c

data段地址:data_1 = 0x601038

data段地址:data_2 = 0x60103c

再来示例代码

程序1:

int array[30000];

int main() {

return 0;

}

程序2:

int array[30000] = {1, 2, 3, 4, 5, 6};

int main() {

return 0;

}

发现【程序2】编译之后所得的文件比【程序1】的要大得多。

【程序1】编译后文件大小

【程序2】编译后文件大小

于是使用 objdump -t 反汇编查看变量 array 所处存储位置。

程序1:

objdump -t main | grep array

0000000000600e10 l d .init_array 0000000000000000 .init_array

0000000000600e18 l d .fini_array 0000000000000000 .fini_array

0000000000600e18 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry

0000000000600e10 l O .init_array 0000000000000000 __frame_dummy_init_array_entry

0000000000600e18 l .init_array 0000000000000000 __init_array_end

0000000000600e10 l .init_array 0000000000000000 __init_array_start

0000000000601060 g O .bss 000000000001d4c0 array

最后一行可以看到,【程序1】的 array 位于.bss段。

我们还可以使用 size 命令,查看每个段大小:

size main

text data bss dec hex filename

1099 544 120032 121675 1db4b main

程序2:

objdump -t main | grep array

0000000000600e10 l d .init_array 0000000000000000 .init_array

0000000000600e18 l d .fini_array 0000000000000000 .fini_array

0000000000600e18 l O .fini_array 0000000000000000 __do_global_dtors_aux_fini_array_entry

0000000000600e10 l O .init_array 0000000000000000 __frame_dummy_init_array_entry

0000000000600e18 l .init_array 0000000000000000 __init_array_end

0000000000600e10 l .init_array 0000000000000000 __init_array_start

0000000000601040 g O .data 000000000001d4c0 array

最后一行可以看到,【程序2】的 array 位于.data段。

使用 size 命令,查看每个段大小,因为text,bss,data段在编译时已经决定了进程将占用多少VM:

size main

text data bss dec hex filename

1099 120560 8 121667 1db43 main

此外,再使用 objdump -s 查看【程序2】中.data段中的数据,可以看到很多很多行的数据:

objdump -s main

main: 文件格式 elf64-x86-64

...省略...

Contents of section .data:

601020 00000000 00000000 00000000 00000000 ................

601030 00000000 00000000 00000000 00000000 ................

601040 01000000 02000000 03000000 04000000 ................

601050 05000000 06000000 00000000 00000000 ................

601060 00000000 00000000 00000000 00000000 ................

601070 00000000 00000000 00000000 00000000 ................

601080 00000000 00000000 00000000 00000000 ................

601090 00000000 00000000 00000000 00000000 ................

6010a0 00000000 00000000 00000000 00000000 ................

6010b0 00000000 00000000 00000000 00000000 ................

6010c0 00000000 00000000 00000000 00000000 ................

6010d0 00000000 00000000 00000000 00000000 ................

6010e0 00000000 00000000 00000000 00000000 ................

6010f0 00000000 00000000 00000000 00000000 ................

601100 00000000 00000000 00000000 00000000 ................

601110 00000000 00000000 00000000 00000000 ................

601120 00000000 00000000 00000000 00000000 ................

601130 00000000 00000000 00000000 00000000 ................

...省略很多很多行...

总结

未初始化的全局变量、静态局部变量,存储在.bss段中,具体体现为一个占位符;

已初始化的全局变量、静态局部变量,存储在.data段中;

此外,非静态局部变量,都在栈中分配空间。

.bss 是不占用.exe文件空间的,其内容由操作系统初始化(清零);

.data 却需要占用,其内容由程序初始化。因此造成了上述情况。

bss 段,不为数据分配空间,只是记录数据所需空间的大小;

bss 段的大小从可执行文件中得到 ,然后链接器得到这个大小的内存块,紧跟在data段后面。

data 段,则为数据分配空间,数据保存在目标文件中;

data 段包含经过初始化的全局变量以及它们的值。

c语言编译bss和data,深入理解BSS段与data段的区别相关推荐

  1. (深入理解计算机系统) bss段,data段、text段、堆(heap)和栈(stack)(C/C++存储类型总结)(内存管理)

    文章目录 bss段 data段 text段 堆(heap) 栈(stack) 一个程序本质上都是由 bss段.data段.text段三个组成的. 存储类型总结 bss段 bss段(bss segmen ...

  2. C语言怎么编译成机器语言的,终于理解了编译是怎么回事!从C语言到机器语言的升华过程!...

    看完这篇文章以后,终于明白了编译到底怎么回事.数据库 1 对于同一个语句,有以下三种:高级语言.低级语言.机器语言的表示编程 C语言:windows a=b+1;网络 汇编语言:数据结构 mov -0 ...

  3. 理解Java和C语言编译原理

    C语言代码的编译原理: http://blog.csdn.net/neil_wesley/article/details/51265457 Java语言的编译原理: http://www.cnblog ...

  4. c语言堆、栈、数据段、代码段、bss段的疑惑

    程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(h ...

  5. 关于text段、data段和bss段

    根据APUE,程序分为下面的段:.text, data (initialized), bss, stack, heap. data/bss/text: text段在内存中被映射为只读,但.data和. ...

  6. C语言编译全过程剖析

    一. 摘要 C语言编译的整个过程是非常复杂的,里面涉及到的编译器知识.硬件知识.工具链知识都是非常多的,深入了解整个编译过程对工程师理解应用程序的编写是有很大帮助的,希望大家可以多了解一些,在遇到问题 ...

  7. linux代码段映射,bss,data,text,rodata,堆,栈,常量段与其各段在物理存储中关系

    本文想从linux出发[目前还想可不可以从51单片机出发],解答程序代码和各种数据结构是如何存储(映射)到存储区的. 目前未完成整理,还是初稿的想法.bss段: BSS段(bsssegment)通常是 ...

  8. c语言代码存放的区域 堆栈,C语言中内存分布及程序运行中(BSS段、数据段、代码段、堆栈)...

    BSS段:(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属于静态内存分配. 数据段 :数据 ...

  9. C语言编译过程分析及实验验证

    一. 实验情况概述 本次实验完成了以下要求: 编写的一个简单C语言例子(至少包括3个C文件.至少一个头文件:含有初始化全局变量.未初始化全局变量.函数内静态变量与局部变量.赋值语句.if语句等),尽量 ...

  10. stm32中堆、栈、flash、ROM、RAM、bss段、data段、text段、Code、Ro-data、 ZI-data、RW-data简介

    1. 堆.栈.flash.ROM.RAM.bss段.data段.text段.Code.Ro-data ZI-data.RW-data的区别? 1.1 堆.栈简介 堆栈是指在stm32启动文件中定义的那 ...

最新文章

  1. unity开发入门_Unity游戏开发终极入门指南
  2. 加密解密基础问题:字节数组和(16进制)字符串的相互转换
  3. 【学术相关】你只看到了200万年薪的招聘,看不到被困校园的几十万博士
  4. linux双核对线程,Linux检查双核(及多核)CPU信息
  5. Sublime Text 3 插件安装
  6. eclipse 隐藏项目_前5个有用的隐藏Eclipse功能
  7. Spring Data JPA 从入门到精通~JpaSpecificationExecutor的使用方法
  8. ExtJs与jQuery的比较
  9. hive udaf_Hive UDAF 函数的编写
  10. 企业混合云的VERITAS数据保护方案
  11. macosx安装之旅(1)-硬盘安装
  12. 周末内部常用的15款开发者工具
  13. mysql与_mysql常见的运算符及使用
  14. PHP 微信小程序 WebSocket MySQL Redis实现聊天功能
  15. 2021年PMP考试模拟题11(含答案解析)
  16. 校园跑腿的优势和劣势
  17. 如何用地推进行有效获客降低成本提高效率?
  18. mybatis 自动填充无效_mybatisPlus踩坑之--自动填充
  19. python+adb命令实现自动刷视频脚本
  20. 【web前端期末大作业】基于html+css+javascript+jquery技术设计的音乐网站(44页)

热门文章

  1. DSP28035的CLA使用经验
  2. android 手机内存uri_[Android]Android数据的四种存储方式 - Ron Ngai - 博客园
  3. C语言银行排队系统仿真
  4. 《巴菲特致股东的信》十年期固定行使价格期权对公司的侵蚀-计算过程演示
  5. java 毫秒转分钟和秒_将毫秒转换为分钟和秒的java程序
  6. 究竟是昨天(2.3)立春还是今天(2.4)立春?易语言告诉你真相
  7. zblog html代码,zblog代码大全,代码对应的中文,超详细
  8. Acmer--弱水三千,只取一瓢
  9. 【电力电子】【2014.08】电力电子系统公用接口的三相功率因数校正设计
  10. uc android 面试题,一道新浪UC部门软件测试面试题