编译器初始化全局变量,并分配虚拟内存
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
http://www.cnblogs.com/lovers/p/memory.html
编译器初始化全局变量,并分配虚拟内存
目录
问题:
全局变量arr占用100MB空间,arr存放在静态存储区,当程序运行的时候,占用的内存竟然只有几百KB,难道arr没有占用内存?
解释:
执行文件的大小
例程1、2、3、4可以证明:
数据段保存在目标文件中。
BSS段不保存在目标文件中(除了记录BSS段在运行时所需要的大小)。
该结论引自《C专家编程》6.2节。
执行文件的大小 = BSS段 + 数据段 + 文本段 + 其他。
例程 |
执行文件大小 |
7376Byte = 7.2KB |
|
140865010Byte = 134.3MB |
|
7415Byte=7.2KB |
|
140865045Byte = 134.3MB |
初始化 |
执行文件大小 |
没有显示初始化 |
7376Byte = 7.2KB |
显示初始化 |
140865010Byte = 134.3MB |
什么时候初始化?
1. 手动初始化
编译时根据赋值进行初始化,存储在数据段
2. 默认初始化
编译时初始化,只是记录其大小,存储在BSS段
BSS段的值全是0,由此可见为什么默认初始化int是0,char是空了。对于内部类型和枚举默认初始化是0.
什么时候分配内存?
编译完,全局变量占用的空间就分配好了。
编译器给arr[100 * 1024 * 1024]分配的虚拟内存:
0x804a040
…………
0xe44a03f
结合例程5和例程6的结果可知,无论是否显示初始化,编译后全局变量的内存都分配好了,都是虚拟内存。
为什么程序开始运行时的内存是0.5MB而不是100MB?
例程 |
是否使用全局变量arr |
进程占用内存 |
不使用 |
0.5MB |
|
0.5MB |
||
在main方法中使用全局变量arr memset(arr,1,100*1024*1024) |
100.85MB |
|
100.85MB |
TODO:下面的论述都是跟同学讨论,上网查找的结果,没有经过权威验证。
关于虚拟内存管理请查看:Linux C编程一站式学习----虚拟内存管理
程序开始运行时,并不会真的把静态存储区全部载入实际内存,只把一部分虚拟内存映射到了实际内存,所以没有访问全局变量arr的时候,进程实际占用内存只有几百KB。当访问全局变量的时候,操作系统才会把这一部分虚拟内存地址映射到实际内存,进程实际占用内存才会到达100多MB。
也就是说编译器给全局变量分配的虚拟内存,而我们看到的进程占用的实际内存。
总结:
根据实验可知,全局变量确实是在编译时,初始化和分配虚拟内存。只不过一些实现细节对我们透明了。纸上得来终觉浅,绝知此事要躬行。
实验:
环境
FC18
GCC
例程1 没有显示初始化
源码:
#include <unistd.h>
char arr[100 *1024 *1024];//声明了100MB空间,没有显示初始化
intmain(intargc,char*argv[])
{
while(1)
{
sleep(1);
}
return0;
}
汇编:
.file "test_uninitialized.cpp"
.globlarr
.bss #未初始化
.align 32
.type arr, @object
.size arr, 104857600
arr:
.zero 104857600
.text
.globlmain
.type main, @function
main:
..............
结果:
运行时占用的内存:
内存总共大小:508740KB /1024 = 497MB 约为 512MB
进程占用内存:508740KB * 0.001 = 508.74KB /1024 = 0.5MB
分析:
test_uni的大小为7376字节。
bss段是未初始化的全局变量存储区。100 * 1024 * 1024 = 104857600字节。
例程2 显示初始化
源码:
#include <unistd.h>
char arr[100 *1024 *1024]={'a'};//显示初始化
int main(int argc,char*argv[])
{
while(1)
{
sleep(1);
}
return0;
}
汇编:
.file "test_initialized.cpp"
.globlarr
.data #需要初始化
.align 32
.type arr, @object
.size arr, 104857600
arr:
.byte 97
.zero 104857599
.text
.globlmain
.type main, @function
main:
..............
结果:
运行时占用的内存:
内存总共大小:508740KB /1024 = 497MB 约为 512MB
进程占用内存:508740KB * 0.001 = 508.74KB /1024 = 0.5MB
例程3 没有显示初始化,在main方法中使用全局变量
源码:
#include <unistd.h>
#include <string.h>
char arr[100*1024*1024]; //声明了100MB空间,没有显示初始化
int main(int argc,char*argv[])
{
memset(arr,1,100*1024*1024); //给arr数组全赋值为1
while(1)
{
sleep(1);
}
return0;
}
汇编:
.file "test_uninitialized2.cpp"
.globlarr
.bss
.align 32
.type arr, @object
.size arr, 104857600
arr:
.zero 104857600
.text
.globlmain
.type main, @function
main:
..............
结果:
与例程1的结果相比,没有多少差别。
运行时占用的内存:
内存总共大小:508740KB /1024 = 497MB 约为 512MB
进程占用内存:508740KB * 0.203 = 103274.22KB /1024 = 100.85MB
例程4 显示初始化,在main方法中使用全局变量
源码:
#include <unistd.h>
#include <string.h>
char arr[100*1024*1024]={'a'};//声明了100MB空间,显示初始化
int main(int argc,char*argv[])
{
memset(arr,1,100*1024*1024); //给arr数组全赋值为1
while(1)
{
sleep(1);
}
return0;
}
汇编:
.file "test_initialized2.cpp"
.globlarr
.data
.align 32
.type arr, @object
.size arr, 104857600
arr:
.byte 97
.zero 104857599
.text
.globlmain
.type main, @function
main:
..............
结果:
与例程2的结果相比,没有多少差别。
运行时占用的内存:
内存总共大小:508740KB /1024 = 497MB 约为 512MB
进程占用内存:508740KB * 0.203 = 103274.22KB /1024 = 100.85MB
例程5 没有显示初始化,打印虚拟内存地址
源码:
#include <unistd.h>
#include <stdio.h>
char arr[100*1024*1024];
int main(int argc,char*argv[])
{
printf("address of arr[0] = %p\n",&arr[0]);
printf("address of arr[100 * 1024 * 1024 - 1] = %p\n",&arr[100*1024*1024-1]);
while(1)
{
sleep(1);
}
return0;
}
结果:
arr[100 * 1024 * 1024]的内存分布:
0x804a040
…………
0xe44a03f
上述空间为100MB
查看虚拟内存地址:
08048000-08049000
08049000-0804a000
0804a000-0804b000
0804b000-0e44b000// 100MB空间
最后两段是数据段,其中红色是BSS段
例程6 显示初始化,打印虚拟内存地址
源码:
#include <unistd.h>
#include <stdio.h>
char arr[100*1024*1024]={'a'};
int main(int argc,char*argv[])
{
printf("address of arr[0] = %p\n",&arr[0]);
printf("address of arr[100 * 1024 * 1024 - 1] = %p\n",&arr[100*1024*1024-1]);
while(1)
{
sleep(1);
}
return0;
}
结果:
与例程5的内存地址一样!!神奇地证明了进程中使用的内存地址都是虚拟的。
arr[100 * 1024 * 1024]的内存分布:
0x804a040
…………
0xe44a03f
上述空间为100MB
查看虚拟内存地址:
08048000-08049000
08049000-0804a000
0804a000-0e44b000// 约为100 MB空间
最后一段是数据段,不同的是例程6没有BSS段
作者:loverszhaokai
出处:http://www.cnblogs.com/lovers
本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。