博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
程序的内存分布 - 以 Linux 为例,基于 C 语言分析
阅读量:4705 次
发布时间:2019-06-10

本文共 3397 字,大约阅读时间需要 11 分钟。

这里以 Linux 为例,用 C 语言进行演示。

内存模型

- 内存空间名称 内容 读写操作 分配时机
高地址 kernel 内核空间 命令行参数、环境变量等 不可读写 程序运行时
- stack 栈空间 局部变量 可读写 程序运行时
- heap 堆空间 malloc() new() 内存分配函数创建 可读写 程序运行时
- 全局数据空间(初始化的和未初始化的) 静态变量、全局变量 可读写 编译时
- 只读数据空间 程序的只读数据(常量) 只读 编译时
低地址 代码段 程序的机器码,相同程序的多个运行实体之间共享 只读 编译时
  • 任何对代码段的写操作都会导致 segmentation fault 段错误
  • 常量、静态变量、全局变量都是在编译时分配内存空间

查看可执行文件的结构

size 查看可执行文件的内存分布

可以通过 size 命令查看可执行文件的内存分配,其中 text 的大小对应程序的只读空间(代码段和只读数据段),data 对应初始化了的全局数据、静态变量,bss 是未初始化数据段,包含未经初始化的全局变量和静态变量。详细例子可以参考:

#include 
int b;int main(){
int a = 888;}

上面代码中有未初始化的全局变量,编译后用 size 查看:

[root@VM_139_38_centos 20190121]# size build    text	   data	    bss	    dec	    hex	filename   1127	    540	     12	   1679	    68f	build

修改 C 代码,初始化全局变量:

#include 
int b = 666;int main(){
int a = 888;}

初始化全局变量后,编译后用 size 查看:

[root@VM_139_38_centos 20190121]# size build    text	   data	    bss	    dec	    hex	filename   1127	    544	      8	   1679	    68f	build

nm 查看可执行文件的标签

# nm build 000000000060102c D b0000000000601030 B __bss_start0000000000601030 b completed.63550000000000601028 D __data_start0000000000601028 W data_start0000000000400430 t deregister_tm_clones00000000004004a0 t __do_global_dtors_aux0000000000600e18 t __do_global_dtors_aux_fini_array_entry0000000000400588 R __dso_handle0000000000600e28 d _DYNAMIC0000000000601030 D _edata0000000000601038 B _end0000000000400574 T _fini00000000004004c0 t frame_dummy0000000000600e10 t __frame_dummy_init_array_entry00000000004006b8 r __FRAME_END__0000000000601000 d _GLOBAL_OFFSET_TABLE_                 w __gmon_start__00000000004003a8 T _init0000000000600e18 t __init_array_end0000000000600e10 t __init_array_start0000000000400580 R _IO_stdin_used                 w _ITM_deregisterTMCloneTable                 w _ITM_registerTMCloneTable0000000000600e20 d __JCR_END__0000000000600e20 d __JCR_LIST__                 w _Jv_RegisterClasses0000000000400570 T __libc_csu_fini0000000000400500 T __libc_csu_init                 U __libc_start_main@@GLIBC_2.2.500000000004004ed T main0000000000400460 t register_tm_clones0000000000400400 T _start0000000000601030 D __TMC_END__

strings 查看可执行文件的常量

[root@VM_139_38_centos 20190121]# strings build /lib64/ld-linux-x86-64.so.2Z%1Xlibc.so.6printf__libc_start_main__gmon_start__GLIBC_2.2.5UH-8UH-8[]A\A]A^A_address: const is:%p global is %p local is %p function main is %p;*3$"...

下面的例子演示了各种类型变量常量的内存地址的位置:

#include 
const int a = 666;int b = 777;char * str = "hello\n";int main(){
int c = 888; printf("address: \nconst is:%p\n global is %p\n local is %p\n function main is %p\n string str is %p", &a, &b, &c, main, &str); unsigned char * p = main; //p[0] = 0x0; // 这里访问只读的代码段会报错 str[3] = 'z'; // 这里访问只读的代码段会报错}

输出为:

address: const is:0x400600 global is 0x601034 local is 0x7ffdb921023c function main is 0x40052d string str is 0x601040

堆和栈的区别

只读空间在程序运行之前就分配好了,运行结束后才回收。

管理方式和分配方式不同

  • 程序的栈由编译器自动管理。程序运行时每个函数的变量放在栈 stack 中,函数返回时函数中的局部变量出栈释放。
  • 程序的堆是动态分配的,由代码控制。可以通过 malloc() 和 free() 函数动态扩展和缩减(C++ 中对应 new() 和 delete()),malloc 可以参考:
#include 
#include
int main(){
char *p = (char *)malloc(100); if (p == NULL) exit(1); int *a; a = (int *)malloc(sizeof(int)); if (a == NULL) {
free(p); exit(1); } free(a); printf("end");}

碎片水平不同

  • 堆的分配和回收会造成内存空间的不连续,造成大量的碎片,使程序效率降低。
  • 栈不存在碎片问题,因为栈是先进后出的队列,永远不可能有一个内存块从栈中间弹出。

转载于:https://www.cnblogs.com/kika/p/10851507.html

你可能感兴趣的文章
WPF实现3D翻转的动画效果
查看>>
自定义圆环进度条
查看>>
UILayer
查看>>
复杂对象写入文件
查看>>
k8s-高级调度方式-二十一
查看>>
[HDU3555]Bomb
查看>>
基于dubbo的分布式系统(一)安装docker
查看>>
Recursion
查看>>
66. Plus One
查看>>
COMP30023 Computer Systems 2019
查看>>
CSS选择器分类
查看>>
Kali学习笔记39:SQL手工注入(1)
查看>>
C# MD5加密
查看>>
Codeforces Round #329 (Div. 2)D LCA+并查集路径压缩
查看>>
移动应用开发测试工具Bugtags集成和使用教程
查看>>
Java GC、新生代、老年代
查看>>
Liferay 6.2 改造系列之十一:默认关闭CDN动态资源
查看>>
多线程
查看>>
折线切割平面
查看>>
获取当前路径下的所有文件路径 :listFiles
查看>>