编译器初始化全局变量,并分配虚拟内存
2013-10-12 18:14
225 查看
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明
/article/6992251.html
word版下载
编译器初始化全局变量,并分配虚拟内存... 1
问题:... 1
解释:... 1
执行文件的大小... 1
什么时候初始化?... 2
什么时候分配内存?... 3
为什么程序开始运行时的内存是0.5MB而不是100MB?... 3
总结:... 3
实验:... 3
环境... 3
例程1 没有显示初始化... 4
例程2 显示初始化... 5
例程3 没有显示初始化,在main方法中使用全局变量... 7
例程4 显示初始化,在main方法中使用全局变量... 9
例程5 没有显示初始化,打印虚拟内存地址... 11
例程6 显示初始化,打印虚拟内存地址... 12
数据段保存在目标文件中。
BSS段不保存在目标文件中(除了记录BSS段在运行时所需要的大小)。
该结论引自《C专家编程》6.2节。
执行文件的大小 = BSS段 + 数据段 + 文本段 + 其他。
编译时根据赋值进行初始化,存储在数据段
2. 默认初始化
编译时初始化,只是记录其大小,存储在BSS段
BSS段的值全是0,由此可见为什么默认初始化int是0,char是空了。对于内部类型和枚举默认初始化是0.
编译器给arr[100 * 1024 * 1024]分配的虚拟内存:
0x804a040
…………
0xe44a03f
结合例程5和例程6的结果可知,无论是否显示初始化,编译后全局变量的内存都分配好了,都是虚拟内存。
TODO:下面的论述都是跟同学讨论,上网查找的结果,没有经过权威验证。
关于虚拟内存管理请查看:Linux C编程一站式学习----虚拟内存管理
程序开始运行时,并不会真的把静态存储区全部载入实际内存,只把一部分虚拟内存映射到了实际内存,所以没有访问全局变量arr的时候,进程实际占用内存只有几百KB。当访问全局变量的时候,操作系统才会把这一部分虚拟内存地址映射到实际内存,进程实际占用内存才会到达100多MB。
也就是说编译器给全局变量分配的虚拟内存,而我们看到的进程占用的实际内存。
GCC
char arr[100 *1024 *1024];//声明了100MB空间,没有显示初始化
intmain(intargc,char*argv[])
{
while(1)
{
sleep(1);
}
return0;
}
.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
bss段是未初始化的全局变量存储区。100 * 1024 * 1024 = 104857600字节。
char arr[100 *1024 *1024]={'a'};//显示初始化
int main(int argc,char*argv[])
{
while(1)
{
sleep(1);
}
return0;
}
.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
#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;
}
.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
#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;
}
.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
#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段
#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段
/article/6992251.html
word版下载
编译器初始化全局变量,并分配虚拟内存
目录编译器初始化全局变量,并分配虚拟内存... 1
问题:... 1
解释:... 1
执行文件的大小... 1
什么时候初始化?... 2
什么时候分配内存?... 3
为什么程序开始运行时的内存是0.5MB而不是100MB?... 3
总结:... 3
实验:... 3
环境... 3
例程1 没有显示初始化... 4
例程2 显示初始化... 5
例程3 没有显示初始化,在main方法中使用全局变量... 7
例程4 显示初始化,在main方法中使用全局变量... 9
例程5 没有显示初始化,打印虚拟内存地址... 11
例程6 显示初始化,打印虚拟内存地址... 12
问题:
全局变量arr占用100MB空间,arr存放在静态存储区,当程序运行的时候,占用的内存竟然只有几百KB,难道arr没有占用内存?解释:
执行文件的大小
例程1、2、3、4可以证明:数据段保存在目标文件中。
BSS段不保存在目标文件中(除了记录BSS段在运行时所需要的大小)。
该结论引自《C专家编程》6.2节。
执行文件的大小 = BSS段 + 数据段 + 文本段 + 其他。
例程 | 执行文件大小 |
例程1 | 7376Byte = 7.2KB |
例程2 | 140865010Byte = 134.3MB |
例程3 | 7415Byte=7.2KB |
例程4 | 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 | 进程占用内存 |
例程1 | 不使用 | 0.5MB |
例程2 | 0.5MB | |
例程3 | 在main方法中使用全局变量arr memset(arr,1,100*1024*1024) | 100.85MB |
例程4 | 100.85MB |
关于虚拟内存管理请查看:Linux C编程一站式学习----虚拟内存管理
程序开始运行时,并不会真的把静态存储区全部载入实际内存,只把一部分虚拟内存映射到了实际内存,所以没有访问全局变量arr的时候,进程实际占用内存只有几百KB。当访问全局变量的时候,操作系统才会把这一部分虚拟内存地址映射到实际内存,进程实际占用内存才会到达100多MB。
也就是说编译器给全局变量分配的虚拟内存,而我们看到的进程占用的实际内存。
总结:
根据实验可知,全局变量确实是在编译时,初始化和分配虚拟内存。只不过一些实现细节对我们透明了。纸上得来终觉浅,绝知此事要躬行。实验:
环境
FC18GCC
例程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段
相关文章推荐
- 编译器给未初始化的全局变量和局部变量分配的存储值
- LCC编译器的源程序分析(69)全局变量的初始化
- 刨根问底:C++中未初始化全局变量为什么都会被编译器自动置0
- C语言中的全局变量内存分配和初始化顺序
- LCC编译器的源程序分析(69)全局变量的初始化
- C++中全局变量的编译器初始化值
- LCC编译器的源程序分析(69)全局变量的初始化
- 全局变量如果不初始化,则默认为0,编译时编译器不提示“变量未初始化”
- LCC编译器的源程序分析(69)全局变量的初始化
- LCC编译器的源程序分析(69)全局变量的初始化
- C语言中的全局变量内存分配和初始化顺序
- 全局变量如果不初始化,则默认为0,编译时编译器不提示“变量未初始化”。
- LCC编译器的源程序分析(69)全局变量的初始化
- 全局变量,静态全局变量,静态局部变量,类静态成员内存分配与初始化问题
- LCC编译器的源程序分析(69)全局变量的初始化
- LCC编译器的源程序分析(69)全局变量的初始化
- LCC编译器的源程序分析(69)全局变量的初始化
- LCC编译器的源程序分析(69)全局变量的初始化
- LCC编译器的源程序分析(69)全局变量的初始化
- LCC编译器的源程序分析(69)全局变量的初始化