内存、堆栈和各种变量的理解

        其实早就想梳理下这些知识点,一直碍于没有合适的时间,没有合适的心情(那是一种feel,😂),今天大致梳理一下这些知识点,记录一下。

1、内存

       有时候大家听到内存这个词也许会根flash存储混淆,其实这个也很正常,在我还没有接触计算机和技术相关的事情的时候,我也不清楚,大家经常说自己手机内存不够了,16G,32G不够用等等之类的,其实正确的叫法应该是flash存储不够用,而不是叫做内存。内存是什么,内存是cpu加载程序运行的地方,我们系统运行起来以后基本所有的操作都在内存中执行,此时我们都可以把我们的硬盘拔掉(SSD或者机械硬盘,SSD本质上就是flash的存储,只是它集结了很多颗flash然后组合在一起的大存储而已,机械硬盘和SSD可以看成是一个东西,存储介质)。拔掉硬盘后,我们的系统还是可以照常在内存中运行,就像我们的笔记本电脑的内存条,终端设备也有内存条,只是大家都不关心它而已,只知道"内存"32G不够用了,而忽略了运行的内存的存在。这个只是普及一下内存和存储的区别,我现在要说的这个内存重点不是在这儿,我想记录的重点是内存中都存放些什么,他的存储分配是什么样子的。

     作为一个开发者,我们在开发程序的时候,会关心我们的程序在内存中的存放形式和结构,下面将介绍下一个运行的程序在内存中是有哪些分布:内存的分布主要包括栈、堆,全局存储区(静态存储区),常量区金额程序代码区。

a、堆(heap) :堆的空间一般由程序员自己分配和释放, 若程序员不释放,程序结束时可能由OS回收 。malloc和new等操作实际上就是在堆中申请内存,对象使用完后要手动释放,否则只能等待程序结束时由系统回收,这时将会产生内存泄漏。

b、栈(stack):栈是由编译器自动分配释放,例如函数的参数值,局部变量的值等都存放在栈空间里面,栈的空间很小,一般在1MB左右。

c、全局区(静态区)(static):全局区存放着全局变量和静态变量,初始化过的全局变量和静态变量在同一块区域,未初始化的全局变量和静态变量存放在一块相邻的区域,此区域由系统在程序结束后释放,不需要开发者手动申请和释放。

d、常量区:像宏定义的常量字符串、整数等存放在此区域,在程序结束后由系统释放。

e、程序代码区:存放函数体的二进制代码,就是代码运行时的相关数据,包括一些静态动态库,主函数代码等。

2、对比一下堆栈的不同点

a、分配方式不同,栈是由系统自己分配,而堆则是开发者通过malloc和new方式自己分配,而且使用完后必须自己释放,否则将会出现内存泄漏。

b、分配效率不同,栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执 行,所以说栈操作是CPU直接操作的内存寄存器,直接这就决定了栈的效率比较高;而像malloc和new这种申请堆的方式是C++库提供的方法,它的机制是很复杂的,类似于C++自己封了一层库去处理管理和控制内存寄存器,所以这样肯定会存在时差,效率肯定没有栈那么高。

c、空间不同,栈的空间一般很小在VC6下面,默认的栈空间是1MB,可能在有些嵌入式设备下栈的空间更小,而堆就不同了,它可以分配更大的空间资源,只要内存足够大,按理论来说想分多大就分多大

d、碎片问题:

对于栈来说,不存在碎片问题,因为是直接操作的内存寄存器,只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出

而对于堆来说却不一样,因为堆的大小是不确定的,是开发者自己申请释放的。先大致说下内存怎么申请的:假如说你要去申请4K的内存,然后C++的库就会按照你所需要的内存大小去寻找4K大小的空闲内存,慢慢的后面就会有更多的内存申请,比如说64K,128K等申请,期间也伴随着之前申请的内存被释放,此时你的内存区域可能就存在这种现象,就是一段内存从左到右断断续续的有空闲内存,有在使用的内存,这就是大家常提及的内存碎片化。内存碎片化后就会存在一种不好的现象,就是假如说你要申请一段稍大一点的内存,但是在内存中找不到这样刚好大小的连续的内存区域,那么此时C++库的做法就是会挑几个空闲的内存拼接起来,形成一个你申请的内存空间,大家都知道如果这样申请的内存访问起来肯定没有连续的访问起来效率高,这样性能就会存在问题,这也是内存碎片化后导致的后果。

e、生长方向不同,生长方向不同就是说在堆栈申请的先后顺序,内存地址是逐渐变大还是变小来说的。栈是向下生长的,就是说你在函数体内部先后定义了两个局部变量(局部变量的内存空间的申请是属于栈空间管理),当你查看它地址的时候你会发现你先定义的变量的内存地址要比你后定义的内存地址要大,对于数组局部变量int data[10],你会发现data[1]要比data[0]的地址小;而堆是向上生长的,就是说你先申请的变量的地址比后申请的变量地址要小,对于malloc申请的内部地址你会发现是从小到大的,和栈的数组地址生长方向相反。

3、变量

在前面也提到过变量,变量分很多种,静态变量,全局变量,局部变量等等。变量有以下几个特性:变量生存周期,变量作用域,变量分配方式。

变量生存周期:生存周期就是指这个变量什么时候产生,什么时候消失,用通俗的话说就是这个变量的从出生到死亡经理的周期。

变量作用域:作用域的意思就是这个变量在什么地方起作用,作用于于谁,例如局部变量指作用于该函数内部,函数调用结束后,变量生命周期也结束,作用域也不再存在。

变量分配方式:分配方式指的是这个变量由谁来主动分配,其实前面也提到过,例如像局部变量,静态变量等是由编译器或者说是系统给他分配,开发人员不需要关注,但是像堆这种申请的变量,就是开发者给它分配,而且如果不需要或者不用了开发者还要将其释放。

下面大致说说几种常用的变量的理解:

a、全局变量:该变量具有全局作用域。全局变量只需在一个源文件中定义,就可以作用于所有的源文件。当然,其他不包含全局变量定义的源文件需要用extern 关键字再次声明这个全局变量。

b、局部变量:该变量也只有局部作用域,它只作用于该函数体内,它在程序运行期间不是一直存在,而是只在函数执行期间存在,函数的一次调用执行结束后,变量被撤销,其所占用的内存也被收回。

c、静态局部变量:该变量具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有的函数都是可见的,而静态局部变量只对定义自己的函数体始终可见(有种站着茅坑有时候拉屎,有时候不拉的感觉,但是它就要一直占着位置)。

d、静态全局变量:该变量也具有全局作用域,它与全局变量的区别在于如果程序包含多个文件的话,它作用于定义它的文件里,不能作用到其它文件里,即被static关键字修饰过的变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量(这句感觉很重要,这个是我当时理解的重点)

小结

从分配内存空间看:全局变量,静态局部变量,静态全局变量都在静态存储区分配空间,而局部变量在栈里分配空间。从以上分析可以看出, 把局部变量改变为静态局部变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态全局变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。

 

 

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值