内存中的栈区和堆区
C程序在内存分为5个区:栈区、堆区、静态区、常量区、代码区。
1、栈区:由编译器自动分配释放, 存放函数的参数值,局部变量等,其操作方式类似于数据结构中的栈(向低地址)。
2、堆区:就是通过new、malloc、realloc分配的内存块,由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收 。分配方式类似于数据结构中的链表。“内存泄漏”通常说的就是堆区。(向高地址增长)
3、全局区:存放全局变量和静态变量以及常量
(1)静态区:存储全局变量和静态变量,程序结束后,由系统释放。
(2)常量区
4、代码区:顾名思义,存放代码。
【精选】C语言的内存分配{静态内存&动态内存&堆栈}_c语言内存-CSDN博客
程序运行前
在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
代码区:
存放 CPU 执行的机器指令
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
全局区:
全局变量和静态变量存放在此.
全局区还包含了常量区, 字符串常量和其他常量也存放在此.
该区域的数据在程序结束后由操作系统释放.
在上面基础上,讨论变量有三种内存分配方式:
1、从静态存储区域分配。内存格局在程序编译的时候就已经明确好了,静态变量也都初始化好了,这块内存在程序的整个运行期间都存在,例如全局变量,static变量。
2、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放,栈内存分配运算内置于处理器的指令集中,效率很高,凡是分配的内存容量有限。例如 int a[10]。
3、从堆上分配。也称动态内存分配。程序在运行的时候用malloc或者new申请任意多少的内存,程序员自己负责在何时用free或者delete释放内存。动态内存的生存期有程序员决定,使用非常灵活,但如果在堆上分配了空间,就有责任回收他。否则运行的程序会出现内存泄漏,频繁的分配和释放不同大小的堆空间将会产生堆内碎块。
对应C/C++ 中变量的三种存储形式:
- 静态存储:声明变量的时候前面添加static关键字;
- 自动存储: 这个举个例子,在一个函数A里面定义了一个变量并初始化, int a =10 ; 这个就是自动存储,a仅当A()函数活动时存在。当成许控制权回到main()时,a使用的内存将自动被释放,
- 动态存储:数据的声明周期不完全受程序或函数的生命时间控制 ,所以C++ 中有new 来分配空间,不过由于内存不会自动释放,所以使用完之后还需要使用delete 来释放内存。
————————————————
原文链接:https://blog.csdn.net/qq_35902025/article/details/127764973
栈、堆、静态存储区能申请的最大分配大小是多少呢?
1、栈区:默认大小为2M或1M,开的比较小;如果定义a[1024*1024];运行时就会报”段错误“,遇到要申请大的空间时,就需要动态申请。
一种是:定义的局部数组太大 第二种是 递归深度太深。
2、静态存储区:全局变量,全局数组,静态数组(static)则是开在全局区(静态区)(static)。大小为2G,所以能够开的很大;
3、堆区:堆的最大可分配大小上限是由虚拟内存的最大值决定的。虚拟内存的最大值由
Min(内存容量和外存容量之和,计算机的地址位数能容纳的最大容量) 决定。
总结一下,在默认情况下,栈只能得到1M大小的内存,全局静态储存可以得到2G,而在32位和64位下的堆则可以得到2G和无限内存(一般不会用到16T)。
(5条消息) 关于栈、堆、静态存储区最大可分配大小的探讨_lwnylslwnyls的专栏-CSDN博客
栈、堆(new/malloc)、静态区(static)的大小_堆栈分配4k,可申请静态数组大小为-CSDN博客
堆区/栈区详解
1、栈区
因为栈主要是为一个线程配备(栈是线程独享的)为这个线程的函数调用服务的。用于存放返回地址,参数,临时变量而用,记录多层调用,是一个有明确的“后入先出”规则的内存 buffer。而且是供程序员“隐式”的使用,分配和回收都是“自动”的,程序员对栈内存的使用缺少自由和可控性, 栈这部分内存由专用的寄存器和指令来负责维护。其特点是栈的“复用率”很高,是连续的,且有 IN - OUT 次序的(对 ESP 的维护非常严格严谨,这个工作是编译器来负责,通常也不需要程序员去干预。计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
栈上对象的特点是尺寸小而且生命周期很短, 潜规则是不要创建尺寸极大的临时对象,调用深度也不希望过深。所以如果栈太大,则对内存使用的性价比会降低(栈的顶部方向的那部分属于栈所有但位于栈外的那部分内存是几乎不会被使用到的,距离栈顶越远的栈外内存的被使用的概率越低,距离栈底越近的内存则使用率越高,热点集中在靠近栈底的部分,而远端方向则是空白的,就好像地铁车厢的高度,不会因为一个姚明这样的存在就把它设计的很高,那样就属于浪费),而且也会减少可以同时创建的进程的数量。
栈只能进行push和pop两种操作,无论是排序,寻址,还是修改,删除,插入都很难,时间代价太高了。所以 其实不是不能将栈变得很大,而是因为一旦变得很大,它在这个场景下就不是一个合理的数据结构了,应该选择其他的数据结构来解决。
2、堆区
而堆内存的使用特点是不连续和无序的,分配和释放成本较高堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。 显然,堆的效率比栈要低得多。 ,
因此,栈和堆的设计体现了“分工”原则。栈的主要作用的为函数调用服务,并承担了生命周期很短和(编译器)“自动”维护,尺寸很小的临时对象的存储责任。堆则负责存储生命周期由程序员自主维护,以及尺寸极大的(例如明显超过栈的尺寸)对象/数据。
栈区和堆区大小差异?
栈区:由图中其实可以知道,栈区是向低地址扩展的,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,大小在进程分配时是确定的,具体大小看编译器,操作系统。所需大小一般小于10M!太大没有意义,不符合栈是用来快速存取的目标。
堆区:堆区是向高地址扩展的,是不连续的内存区域(这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的是动态分配的),因为会手动进行分配,会大一些,大小不固定。
栈区和堆区效率差异?
至于堆区和栈区哪个更快,从两方面来考虑:
(1)分配和释放,堆在分配和释放时都要调用函数(MALLOC,FREE),比如分配时会到堆空间去寻找足够大小的空间(因为多次分配释放后会造成空洞),这些都会花费一定的时间,具体可以看看MALLOC和FREE的源代码,他们做了很多额外的工作,而栈却不需要这些,由于栈先进后出的特性存取非常快,实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyorbelt)一样,StackPointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候,修改栈指针就可以把栈中的内容销毁.这样的模式速度最快。
PS:我现在实习的一家量化交易公司,他们就绝不会允许使用malloc在堆区操作,因为堆的分配是离散的,对于他们高频连续的数据存取不是很方便。具体好像是内核旁路技术(搭配网卡)加上多线程(4线程)共享栈内存。什么同步不同步,有时间再继续填坑!
(2)访问时间,访问堆的一个具体单元,需要两次访问内存,第一次得取得指针,第二次才是真正得数据,而栈只需访问一次。另外,堆的内容被操作系统交换到外存的概率比栈大,栈一般是不会被交换出去的。
栈区:由系统自动分配,速度较快。但程序员是无法介入分配。(只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。)
堆区:是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。(首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的 delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中)
小结:其实从上面的知识我们可以看出,如果存放在堆中的数据如果不进行释放,很可能造成内存泄漏,因为并不一定能触发gc机制回收。所以对于堆中的内存使用,我们要记得用完释放。
堆栈缓存方式区别:
1、栈使用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立即释放;
2、堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
参考:
堆、栈、栈区、堆区四者在数据结构和虚拟内存模型中的区别-CSDN博客