栈
-
大小
Linux: 10M = 10240KBwindows: 1M = 1024KB
-
可以静态分配(在编译阶段就能确定大小,由编译器进行分配);
也可以动态分配(使用alloca()函数可以动态分配栈的内存空间,释放的时候由编译器自己释放,不需要手动释放)
堆(链表维护,内存不连续)
-
不能静态分配,只能动态分配(堆的申请是在执行过程中执行的)
堆是使用malloc()、calloc()、realloc()等函数动态分配的
-
在堆上频繁的调用new/delete容易产生内存碎片
进程的内存空间分配方式
进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。
-
代码区(只读)(低地址)
- 程序代码
- 数字常量
-
静态数据区(中地址)
-
字符串常量(只读数据段,挨着数据段)
-
全局变量(已经初始化)
-
静态变量(static修饰)
c语言中static的语义
1.static变量:
1).局部
只初始化一次,静态局部变量存放在内存的全局数据区。函数结束时,静态局部变量不会消失,每次该函数调用时,也不会为其重新分配空间。它始终驻留在全局数据区,直到程序运行结束。
2).全局
2.static函数(也叫内部函数)只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。
-
-
动态数据区(高地址)
- 堆:链式结构(向高地址方向增长)
- 栈:线性结构(函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。)(向低地址方向增长)
- 本地变量
- 程序通过堆栈的基地址和偏移量来访问本地变量。
下图来源:Unix环境高级编程一书中7.6小节
用nm命令查看全局变量在bss段,data段
//test.c
#include <stdio.h>
int global_variable;
int initialized_global_variables = 1;
int add(int a, int b){
return a + b;
}
int main(){
int a = 1;
printf("hello %d\n", add(a, 1));
return 0;
}
局部变量a在栈中,栈和堆在程序运行时才有,所以可执行文件看不到a
[root@izbp1bvlfc3omk6i0e7ht2z C]# nm test.out
/*********************************
000000000040052d T add//静态绑定函数地址
*********************************/
0000000000601038 B __bss_start
0000000000601038 b completed.6355
0000000000601030 D __data_start
0000000000601030 W data_start
0000000000400470 t deregister_tm_clones
00000000004004e0 t __do_global_dtors_aux
0000000000600e18 t __do_global_dtors_aux_fini_array_entry
0000000000400608 R __dso_handle
0000000000600e28 d _DYNAMIC
0000000000601038 D _edata
0000000000601040 B _end
00000000004005f4 T _fini
0000000000400500 t frame_dummy
0000000000600e10 t __frame_dummy_init_array_entry
0000000000400768 r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
/********************************************
000000000060103c B global_variable//未初始化在bss段
********************************************/
w __gmon_start__
000000000040061c r __GNU_EH_FRAME_HDR
00000000004003e0 T _init
0000000000600e18 t __init_array_end
0000000000600e10 t __init_array_start
/********************************************
0000000000601034 D initialized_global_variables//初始化在data段
********************************************/
0000000000400600 R _IO_stdin_used
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
00000000004005f0 T __libc_csu_fini
0000000000400580 T __libc_csu_init
U __libc_start_main@@GLIBC_2.2.5
0000000000400541 T main
/********************************************
U printf@@GLIBC_2.2.5//printf需要运行时动态链接,此时不绑定函数地址
********************************************/
00000000004004a0 t register_tm_clones
0000000000400440 T _start
0000000000601038 D __TMC_END__
static用法和作用
-
声明静态变量
-
全局变量:静态全局变量仅对当前文件可见,其他文件不可访问,避免不同文件变量同名的冲突,降低耦合性。
-
局部变量:存储于进程的全局数据区,编译器自动对其初始化,函数结束,内存空间也不会回收,作用域在函数体内,有利于程序模块化。
-
-
声明函数
- 静态函数只能在声明它的文件中可见,其他文件不能引用该函数
- 不同的文件可以使用相同名字的静态函数,互不影响