c语言存储区 划分

c语言中,存储区可以分成代码区,全局区,常量区,栈,堆;如下图所示: 

全局区 :主要存储全局变量和static变量。

常量区:存放常量的地方。

堆:用户申请的内存区,用编译器提供的函数newmalloc申请。要注意内存泄露的问题

栈:系统自动给局部变量分配的内存区。

 

 

extern关键词:extern修饰全局变量glovar时,表明glovar可以被其他模块的函数使用

              extern修饰函数是,表明函数可以被其他模块的函数调用

static关键词:static修饰局部变量var时,表明var在函数调用结束时不销毁,函数在此被调用时,不对VAR 再次定义,使用上次调用结束时的值,他的生命期:从第一次调用开始,到main结束;

             static修饰全局变量glovar时,表明glovar不能够被其他模块的函数使用;

              static修饰函数是,表明函数不能够被其他模块的函数调用

voltile:表明变量可能在另外的进程修改,因此每次使用时,必须重新从内存读取。




终于知道什么叫BSS段

是“Block Started by Symbol”的缩写,意为“以符号开始的块”。

  BSS是Unix链接器产生的未初始化数据段。其他的段分别是包含程序代码的 “text”段和包含已初始化数据的“data”段。BSS段的变量只有名称和大小却没有值。此名后来被许多文件格式使用,包括PE。“以符号开始的块” 指的是编译器处理未初始化数据的地方。BSS节不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效地清零。BSS节在应用程序 的二进制映象文件中并不存在。

  在采用段式内存管理的架构中(比如intel的80x86系统),bss段(Block Started by Symbol segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。

  比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。

  text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系 统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化。


各个段的关系


图3-1所示为可执行代码存储时结构和运行时结构的对照图。一个正在运行着的C编译程序占用的内存分为代码区、初始化数据区、未初始化数据区、堆区 和栈区5个部分。

(点击查看大图)图3-1 C程序的内存布局

(1)代码区(text segment)。代码区指令根据程序设计流程依次执行,对于顺序指令,则只会执行一次(每个进程),如果反复,则需要使用跳转指令,如果进行递归,则需 要借助栈来实现。

代码区的指令中包括操作码和要操作的对象(或对象地址引用)。如果是立即数(即具体的数值,如5),将直接包含在代码中;如果是局部数据,将在栈区 分配空间,然后引用该数据地址;如果是BSS区和数据区,在代码中同样将引用该数据地址。

(2)全局初始化数据区/静态数据区(Data Segment)。只初始化一次。

(3)未初始化数据区(BSS)。在运行时改变其值。

(4)栈区(stack)。由编译器自动分配释放,存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈。每当一个函数被调用,该函 数返回地址和一些关于调用的信息,比如某些寄存器的内容,被存储到栈区。然后这个被调用的函数再为它的自动变量和临时变量在栈区上分配空间,这就是C实现 函数递归调用的方法。每执行一次递归函数调用,一个新的栈框架就会被使用,这样这个新实例栈里的变量就不会和该函数的另一个实例栈里面的变量混淆。

(5)堆区(heap)。用于动态内存分配。堆在内存中位于bss区和栈区之间。一般由程序员分配和释放,若程序员不释放,程序结束时有可能由OS 回收。

之所以分成这么多个区域,主要基于以下考虑:

一个进程在运行过程中,代码是根据流程依次执行的,只需要访问一次,当然跳转和递归有可能使代码执行多次,而数据一般都需要访问多次,因此单独开辟 空间以方便访问和节约空间。

临时数据及需要再次使用的代码在运行时放入栈区中,生命周期短。

全局数据和静态数据有可能在整个程序执行过程中都需要访问,因此单独存储管理。

堆区由用户自由分配,以便管理。

下面通过一段简单的代码来查看C程序执行时的内存分配情况。相关数据在运行时的位置如注释所述。

//main.cpp
int a = 0;    //a在全局已初始化数据区
char *p1;    //p1在BSS区(未初始化全局变量)
main()
{
int b;    //b在栈区
char s[] = "abc"; //s为数组变量,存储在栈区,
//"abc"为字符串常量,存储在已初始化数据区
char *p1,p2;  //p1、p2在栈区
char *p3 = "123456"; //123456\0在已初始化数据区,p3在栈区
static int c =0;  //C为全局(静态)数据,存在于已初始化数据区
//另外,静态数据会自动初始化
p1 = (char *)malloc(10);//分配得来的10个字节的区域在堆区
p2 = (char *)malloc(20);//分配得来的20个字节的区域在堆区
free(p1);
free(p2);
}

  • 2
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
假设系统的可利用空间容量为2m个字,则系统开始运行时,整个内存是一个大小为2m的空闲分。在系统运行过程中,由于不断的划分,可能会形成若干个不连续的空闲分,将这些空闲分根据分的大小进行分类,对于每一类具有相同大小的所有空闲分,单独设立一个空闲分双向链表。这样,不同大小的空闲分形成了k(0≤k≤m)个空闲分链表。 当需要为进程分配一个长度为n的存储空间时,首先计算一个i值,使2i-1<n≤2i,然后在空闲分大小为2i的空闲分链表中查找。若找到,即把该空闲分分配给进程。否则,表明长度为2i的空闲分已经耗尽,则在分大小为2i+1的空闲分链表中寻找。若存在2i+1的一个空闲分,则把该空闲分分为相等的连个分,这两个分称为一对伙伴,其中的一个分用于分配,而把另一个加入分大小为2i的空闲分链表中。若大小为2i+1的空闲分不存在,则需要查找大小为2i+2的空闲分,若找到则对其进行两次分割:第一次,将其分割为大小为2i+1的两个分,一个用于分配,一个加入到大小为2i+1空闲分链表中;第二次,将第一次用于分配的空闲分分割为2i的两个分,一个用于分配,一个加入到大小为2i空闲分链表中。若仍然找不到,则继续查找大小为2i+3的空闲分,以此类推。由此可见,在最坏的情况下,可能需要对2k的空闲分进行k次分割才能得到所需分。 与一次分配可能要进行多次分割一样,一次回收也可能要进行多次合并,如回收大小为2i的空闲分时,若事先已存在2i的空闲分时,则应将其与伙伴分合并为大小为2i+1的空闲分,若事先已存在2i+1的空闲分时,又应继续与其伙伴分合并为大小为2i+2的空闲分,依此类推。 2.2 伙伴系统的需求 根据伙伴系统算法的思想,我们组对本系统的功能划分为3种: ⑴ 根据伙伴系统算法分配内存 ⑵ 根据伙伴系统算法回收内存 ⑶ 实时查看内存使用的情况

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值