linux 程序内存分布,程序的内存分布 - 以 Linux 为例,基于 C 语言分析

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

内存模型

-

内存空间名称

内容

读写操做

分配时机

高地址

kernel 内核空间

命令行参数、环境变量等

不可读写

程序运行时

-

stack 栈空间

局部变量

可读写

程序运行时

-

heap 堆空间

malloc() new() 内存分配函数建立

可读写

程序运行时

-

全局数据空间(初始化的和未初始化的)

静态变量、全局变量

可读写

编译时

-

只读数据空间

程序的只读数据(常量)

只读

编译时

低地址

代码段

程序的机器码,相同程序的多个运行实体之间共享

只读

编译时

任何对代码段的写操做都会致使 segmentation fault 段错误

常量、静态变量、全局变量都是在编译时分配内存空间

查看可执行文件的结构

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

能够经过 size 命令查看可执行文件的内存分配,其中 text 的大小对应程序的只读空间(代码段和只读数据段),data 对应初始化了的全局数据、静态变量,bss 是未初始化数据段,包含未经初始化的全局变量和静态变量。详细例子能够参考:https://blog.csdn.net/love_gaohz/article/details/50522447,简单示例以下:linux

#include

int b;

int main()

{

int a = 888;

}

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

[root@VM_139_38_centos 20190121]# size build

text data bss dec hexfilename

1127 540 12 1679 68fbuild

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

#include

int b = 666;

int main()

{

int a = 888;

}

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

[root@VM_139_38_centos 20190121]# size build

text data bss dec hexfilename

1127 544 8 1679 68fbuild

nm 查看可执行文件的标签

# nm build

000000000060102c D b

0000000000601030 B __bss_start

0000000000601030 b completed.6355

0000000000601028 D __data_start

0000000000601028 W data_start

0000000000400430 t deregister_tm_clones

00000000004004a0 t __do_global_dtors_aux

0000000000600e18 t __do_global_dtors_aux_fini_array_entry

0000000000400588 R __dso_handle

0000000000600e28 d _DYNAMIC

0000000000601030 D _edata

0000000000601038 B _end

0000000000400574 T _fini

00000000004004c0 t frame_dummy

0000000000600e10 t __frame_dummy_init_array_entry

00000000004006b8 r __FRAME_END__

0000000000601000 d _GLOBAL_OFFSET_TABLE_

w __gmon_start__

00000000004003a8 T _init

0000000000600e18 t __init_array_end

0000000000600e10 t __init_array_start

0000000000400580 R _IO_stdin_used

w _ITM_deregisterTMCloneTable

w _ITM_registerTMCloneTable

0000000000600e20 d __JCR_END__

0000000000600e20 d __JCR_LIST__

w _Jv_RegisterClasses

0000000000400570 T __libc_csu_fini

0000000000400500 T __libc_csu_init

U __libc_start_main@@GLIBC_2.2.5

00000000004004ed T main

0000000000400460 t register_tm_clones

0000000000400400 T _start

0000000000601030 D __TMC_END__

strings 查看可执行文件的常量

[root@VM_139_38_centos 20190121]# strings build

/lib64/ld-linux-x86-64.so.2

Z%1X

libc.so.6

printf

__libc_start_main

__gmon_start__

GLIBC_2.2.5

UH-8

UH-8

[]A\A]A^A_

address:

const is:%p

global is %p

local is %p

function main is %p

;*3$"

...

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

#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

堆和栈的区别

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

管理方式和分配方式不一样

程序的栈由编译器自动管理。程序运行时每一个函数的变量放在栈 stack 中,函数返回时函数中的局部变量出栈释放。

程序的堆是动态分配的,由代码控制。能够经过 malloc() 和 free() 函数动态扩展和缩减(C++ 中对应 new() 和 delete()),malloc 能够参考:https://www.cnblogs.com/Commence/p/5785912.html

#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");

}

碎片水平不一样

堆的分配和回收会形成内存空间的不连续,形成大量的碎片,使程序效率下降。

栈不存在碎片问题,由于栈是先进后出的队列,永远不可能有一个内存块从栈中间弹出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值