一.数据段
数据段中包含 bss与data两个节,其中data节用于保存初始化不为0的全局变量,而bss节用于初始化为0或者尚未初始化的全局变量。
为什么以0作为区分两个节?因为对于bss节来说,不需要在文件中保存变量的初值0,Loader只需要使用一个内容为0的page页面,因此该段并不占用文件的空间。但是对于data节来说,必须在文件中data节保存变量的初值,因此需要占用文件大小,当访问这些变量时会触发页故障,将文件中对应的初值加载到内存中,最终完成初始化。
以下分析bss与data对程序的影响。
bss.c
源代码:
#include <stdio.h>int bss[1024*1024]={0};int main(int argc,char *argv[]){bss[0]=1; printf("pid=%d,bss=%lxn",getpid(),bss);pause();return 0;}可执行文件大小:
-rwxr-xr-x 1 taisimin taisimin 6932 2011-12-07 15:37 bss
段分布:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R 0x4
INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x0058c 0x0058c R E 0x1000
LOAD 0x000f0c 0x08049f0c 0x08049f0c 0x00110 0x400134 RW 0x1000
虚拟内存使用:
08048000-08049000 r-xp 00000000 08:01 9836831 /home/taisimin/linux/optimization/process/bss
08049000-0804a000 r--p 00000000 08:01 9836831 /home/taisimin/linux/optimization/process/bss
0804a000-0804b000 rw-p 00001000 08:01 9836831 /home/taisimin/linux/optimization/process/bss
0804b000-0844b000 rw-p 00000000 00:00 0 【heap】
data.c
源码:
#include <stdio.h>int data[1024*1024]={2};int main(int argc,char *argv[]){data[0]=1; printf("pid=%d,data=%lx,n",getpid(),data);pause();return 0;}可执行文件大小:
-rwxr-xr-x 1 taisimin taisimin 4201272 2011-12-07 15:38 data
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R 0x4
INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00590 0x00590 R E 0x1000
LOAD 0x000f0c 0x08049f0c 0x08049f0c 0x400134 0x40013c RW 0x1000
虚拟内存使用:
08048000-08049000 r-xp 00000000 08:01 9836830 /home/taisimin/linux/optimization/process/data
08049000-0804a000 r--p 00000000 08:01 9836830 /home/taisimin/linux/optimization/process/data
0804a000-0844b000 rw-p 00001000 08:01 9836830 /home/taisimin/linux/optimization/process/data
40000000-4001c000 r-xp 00000000 08:01 7475104 /lib/i386-linux-gnu/ld-2.13.so
从以上数据可以看出:
1.bss的可执行文件大小较小。
2.bss中的的数据段正常,但是在stack段中多出4MB的消耗,而data中的数据段多出4MB的消耗,而没有stack段的消耗。这是因为loader对于bss节采用stack的内存空间进行映射,而对于data节直接采用文件的map方式进行内存映射。
二.变量所在内存区域
如下例所示:
var.c
#include <stdio.h>#define b 10#define c "123"int bss[10]={0};int data[10]={1};const int a=10;static int d;char *s1="hello,worldn";char s2[]="hellow,worldn";int main(int argc,char *argv[]){ return 0;}
使用nm -f sysv var命令查看变量所在取悦
Symbols from var:
Name Value Class Type Size Line Section
__bss_start |0804a07c| A | NOTYPE| | |*ABS*
__data_start |0804a020| D | NOTYPE| | |.data
_edata |0804a07c| A | NOTYPE| | |*ABS*
_end |0804a0cc| A | NOTYPE| | |*ABS*
_fini |0804847c| T | FUNC| | |.fini
_fp_hw |08048498| R | OBJECT|00000004| |.rodata
_init |080482bc| T | FUNC| | |.init
_start |08048320| T | FUNC| | |.text
a |080484a0| R | OBJECT|00000004| |.rodata
bss |0804a0a0| B | OBJECT|00000028| |.bss
completed.6155 |0804a080| b | OBJECT|00000001| |.bss
d |0804a0c8| b | OBJECT|00000004| |.bss
data |0804a040| D | OBJECT|00000028| |.data
data_start |0804a020| W | NOTYPE| | |.data
dtor_idx.6157 |0804a084| b | OBJECT|00000004| |.bss
frame_dummy |080483b0| t | FUNC| | |.text
main |080483d4| T | FUNC|0000000a| |.text
s1 |0804a068| D | OBJECT|00000004| |.data
s2 |0804a06c| D | OBJECT|0000000e| |.data
可以看出const变量存放在rodata节中,即最终存放在text段中。
而s1,s2,data都存放在data节中,而bss存放在bss节中。
三.数据段优化
1.减少一个全局整形变量并不会只减少4B,因为Linux中采用页来分配内存。
2.优化data段带来的影响有限,特别是用户程序,但是对于动态库的数据段做优化,其作用还是很明显,假如,一个动态库被100个进程所依赖执行,当所有进程都在执行时,内存中就会包含100份动态库的数据段,若能减少一个整形全局变量,理论上将会减少4B*100=400B的内存大小。
常用优化方法:
1. 使用nm -f sysv xx |grep -w .data (.bss)方式检查各个小节中的变量。
2.使用const方式来修饰只读的全局变量,从而将其转移到代码段中,利用代码段的共享内存方式来减少内存使用