Linux段管理,BSS段,data段,.rodata段,text段
近期在解决一个编译问题时,一直在考虑一个问题,那就是Linux下可执行程序执行时内存是什么状态,是依照什么方式分配内存并执行的。查看了一下资料。就此总结一下,众所周知。linux下内存管理是通过虚存管理的,在分配内存是并不是在物理内存开辟了一段空间,而是在使用时才分配的。并且是通过段页式管理。
以上比較废话,開始看看程序执行时内存会是什么状态。
在linux下内存分配是以页为单位的。而页是通过段管理。各个段之间是独立的,方便管理。linux程序执行时。能够分为下面几个内存段:
一、BSS段 (bss segment)一般是指用来存放程序中未初始化的全局变量的一块内存区域。
BSS是英文Block
Started by Symbol的简称。
BSS段属于静态内存分配。
该段用于存储未初始化的全局变量或者是默认初始化为0的全局变量,它不占用程序文件的大小,可是占用程序执行时的内存空间。
#define DEBUG "debug" int space[1024][1024]; int main()
{
char *a = DEBUG;
return 1;
}
上面声明了一个space的二维数组,是一个全局变量,没有被初始化。通过nm命令能够查看程序中的符号信息例如以下:
0000000000600660 d _DYNAMIC
00000000006007f8 d _GLOBAL_OFFSET_TABLE_
0000000000400578 R _IO_stdin_used
w _Jv_RegisterClasses
0000000000600640 d __CTOR_END__
0000000000600638 d __CTOR_LIST__
0000000000600650 D __DTOR_END__
0000000000600648 d __DTOR_LIST__
0000000000400630 r __FRAME_END__
0000000000600658 d __JCR_END__
0000000000600658 d __JCR_LIST__
000000000060081c A __bss_start
0000000000600818 D __data_start
0000000000400530 t __do_global_ctors_aux
00000000004003e0 t __do_global_dtors_aux
0000000000400580 R __dso_handle
w __gmon_start__
0000000000600634 d __init_array_end
0000000000600634 d __init_array_start
0000000000400490 T __libc_csu_fini
00000000004004a0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
000000000060081c A _edata
0000000000a00840 A _end
0000000000400568 T _fini
0000000000400358 T _init
0000000000400390 T _start
00000000004003bc t call_gmon_start
0000000000600820 b completed.6347
0000000000600818 W data_start
0000000000600828 b dtor_idx.6349
0000000000400450 t frame_dummy
0000000000400474 T main
0000000000600840 B space
最后一行的B表示是BSS段。也就表示space是存在于BSS段中的。
二、data段 该段用于存储初始化的全局变量,初始化为0的全局变量出于编译优化的策略还是被保存在BSS段,对上面的程序做一下更改就能够看到是怎样分配的了。
#define DEBUG "debug" int space[1024][1024];
int data = 1;
int no_data = 0; int main()
{
char *a = DEBUG;
return 1;
}
使用nm查看后
0000000000600660 d _DYNAMIC
00000000006007f8 d _GLOBAL_OFFSET_TABLE_
0000000000400578 R _IO_stdin_used
w _Jv_RegisterClasses
0000000000600640 d __CTOR_END__
0000000000600638 d __CTOR_LIST__
0000000000600650 D __DTOR_END__
0000000000600648 d __DTOR_LIST__
0000000000400630 r __FRAME_END__
0000000000600658 d __JCR_END__
0000000000600658 d __JCR_LIST__
0000000000600820 A __bss_start
0000000000600818 D __data_start
0000000000400530 t __do_global_ctors_aux
00000000004003e0 t __do_global_dtors_aux
0000000000400580 R __dso_handle
w __gmon_start__
0000000000600634 d __init_array_end
0000000000600634 d __init_array_start
0000000000400490 T __libc_csu_fini
00000000004004a0 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000600820 A _edata
0000000000a00840 A _end
0000000000400568 T _fini
0000000000400358 T _init
0000000000400390 T _start
00000000004003bc t call_gmon_start
0000000000600820 b completed.6347
000000000060081c D data
0000000000600818 W data_start
0000000000600828 b dtor_idx.6349
0000000000400450 t frame_dummy
0000000000400474 T main
0000000000600830 B no_data
0000000000600840 B space
能够看到变量data被分配在data段,而被初始化为0的no_data被分配在了BSS段。
三、.rodata段
该段也叫常量区,用于存放常量数据,ro就是Read Only之意。
可是注意并非全部的常量都是放在常量数据段的。其特殊情况例如以下:
1)有些马上数与指令编译在一起直接放在代码段。
int main()
{
int a = 10;
return 1;
}
a是常量。可是它没有被放入常量区,而是在指令中直接通过马上数赋值
2)对于字符串常量,编译器会去掉反复的常量,让程序的每一个字符串常量仅仅有一份。
char *str = "123456789";
char *str1 = "helloworld"; int main()
{
char* a = "helloworld";
char b[10] = "helloworld";
return 1;
}
汇编代码例如以下:
.file "hello.c"
.globl str
.section .rodata
.LC0:
.string "123456789"
.data
.align 8
.type str, @object
.size str, 8
str:
.quad .LC0
.globl str1
.section .rodata
.LC1:
.string "helloworld"
.data
.align 8
.type str1, @object
.size str1, 8
str1:
.quad .LC1
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movq $.LC1, -8(%rbp)
movl $1819043176, -32(%rbp)
movl $1919907695, -28(%rbp)
movw $25708, -24(%rbp)
movl $1, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.4.6 20110731 (Red Hat 4.4.6-3)"
.section .note.GNU-stack,"",@progbits
能够看到str1和a同一时候指向.rodata段中同一个LC1,而是用数组初始化的字符串常量是没有放入常量区的,另外用const修饰的全局变量是放入常量区的,可是使用cons修饰的局部变量仅仅是设置为仅仅读起到防止改动的效果,没有放入常量区。
3)有些系统中rodata段是多个进程共享的,目的是为了提高空间的利用率。
四、text段
text段是用于存放程序代码的,编译时确定,仅仅读。更进一步讲是存放处理器的机器指令,当各个源文件单独编译之后生成目标文件。经连接器链接各个目标文件并解决各个源文件之间函数的引用,与此同一时候,还得将全部目标文件里的.text段合在一起,但不是简单的将它们“堆”在一起就完事,还须要处理各个段之间的函数引用问题。
五、stack段
也就是栈段,常说的堆栈段之中的一个,是由系统负责申请释放,其操作方式类似stack,用于存储參数变量及局部变量,事实上函数的运行也是stack的方式,所以才有了递归
六、heap段
也就是俗称的堆。它由用户申请和释放。申请时至少分配虚存,当真正存储数据时才分配对应的实存,释放时也并不是马上释放实存。而是可能被反复利用。待兴许会再细致介绍相关的知识。
能够看到堆和栈的内存增长方向是相反的。兴许会对linux的内存管理做具体的介绍
Linux段管理,BSS段,data段,.rodata段,text段的更多相关文章
- Linux中的段管理,bss段,data段,
Linux 的段管理, BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属于静态内存 ...
- linux 目标文件 bss,data,text,rodata,堆,栈***
linux目标文件 一个简单的程序被编译成目标文件后的结构如下: 从图可以看出,已初始化的全局变量和局部静态变量保存在 .data段中,未初始化的全局变量和未初始化的局部静态变量保存在 .bss段中. ...
- 【转】linux代码段,数据段,BSS段, 堆,栈
转载自 http://blog.csdn.net/wudebao5220150/article/details/12947445 linux代码段,数据段,BSS段, 堆,栈 网上摘抄了一些,自己组 ...
- (转)Linux下数据段的区别(数据段、代码段、堆栈段、BSS段)
进程(执行的程序)会占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途 不一而不尽相同,有些内存是事先静态分配和统一回收的, ...
- BSS段 data段 text段 堆heap 和 栈stack
BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域.BSS是英文Block Started by Symbol的简称.BSS段属于静态内存分配. 数 ...
- linux代码段,数据段,BSS段, 堆,栈(二)
//main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = "abc"; 栈 char ...
- [转帖]浅谈程序中的text段、data段和bss段
作者:百问科技链接:https://zhuanlan.zhihu.com/p/28659560来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 一般情况,一个程序本质上都 ...
- [转] bss段、data段、text段
1.前言 一个程序本质上都是由 BSS 段.DATA段.TEXT段三个组成的. 本文主要分编译时和运行时分别对 对data段 bss段 text段 堆 栈作一简要说明 2. 程序编译时概念说明 程序与 ...
- Linux内存管理(text、rodata、data、bss、stack&heap)
一.各内存区段的介绍 系统内的程序分为程序段和数据段,具体又可细分为一下几个部分: (1)text段-代码段 text段存放程序代码,运行前就已经确定(编译时确定),通常为只读,可以直接在ROM或Fl ...
随机推荐
- response.sendRedirect("")和request.getRequestDispatcher("").forward(req,resp);
1:request.getRequestDispatcher("转发路径").forward(req,resp)该语句是实现请求转发的,当请求进入到该servlet中执行到该语句时 ...
- 基于visual Studio2013解决C语言竞赛题之1055排序
题目 解决代码及点评 /* 功能:已知A是有30个元素的整型数组,编写一个对A[I1]到A[I2](I1≤I2)之间的元素排序的函数(从大到小排序) 请调用上述函数先将A[5]至A[ ...
- Not able to reset SmartRF04DD
今天在使用使用CC2540的时候,想下载个程序到CC2540底板上,结果出现Not able to reset SmartRF04DD的错误.如下图 经过一番摸索,最终是按下CCDEBUG上的rese ...
- codility上的问题(15) Xi 2012
进入2012年的题 codility上的题目开始变难,变得有意思起来.给定两个长度在[1..300000]的只包含0和1的串S和T,它们是2进制表示的,S表示的数A不大于T表示的数B,即A<=B ...
- Effective C++_笔记_条款06_若不想使用编译器自动生成的函数,就该明确拒绝
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 通常如果你不希望class支持某一特定机能,只要不声明对应函数就 ...
- Tomcat详细用法学习(四)
本篇接上一篇<Tomcat详细用法学习(三)>,主要讲解配置虚拟主机.打包web应用成war包和Tomcat的体系结构 对于Tomcat服务器,可以放置多个网站(多个web应用),这就是讲 ...
- POJ2782:Bin Packing
Description A set of n<tex2html_verbatim_mark> 1-dimensional items have to be packed in iden ...
- nginx的sendfile指令的作用
linux为了解决对读文件产生的从应用空间到内核空间复制数据产生的效率影响引进了零拷贝.什么是零拷贝?这里就不多说了,请参考http://blog.csdn.net/crazyguang/articl ...
- 流式计算-Jstorm提交Topology过程(上)
Topology是Jstorm对有向无环图的抽象,内部封装了数据来源spout和数据处理单元bolt,以及spout和bolt.bolt和bolt之间的关系.它能够被提交到Jstorm集群. 本文以J ...
- Android事件详解——拖放事件DragEvent
1.Android拖放框架的作用? 利用Android的拖放框架,可以让用户用拖放手势把一个View中的数据移到当前layout内的另一个View中去. 2.拖放框架的内容? 1)拖放事件类 2)拖放 ...