ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

为什么要有堆、栈的根因?

为什么要有堆、栈的根因? 底层本质程序运行时存在两种完全不一样的内存使用模式一类内存生命周期可以在编译期就能确定另一类内存大小、存活时间只有程序跑起来之后才知道。栈服务前者堆服务后者。1、栈stack应对编译期就可知的内存栈内存用于函数局部变量、函数参数、函数返回地址。栈核心特点大小、生命周期编译阶段基本确定调用函数时需要多少局部变量内存编译后就确定。自动管理后进先出LIFO函数进入 → 栈帧压栈函数执行 return → 栈帧直接弹出销毁。不需要程序员手动释放完全自动。空间很小。Linux下线程栈通常几MB。分配释放速度极快只移动栈指针寄存器不需要复杂内核调用。栈适合场景函数内部临时变量函数执行完就不再需要的数据。栈的局限这就是堆诞生的根因之一大小固定不能动态扩容。数组如果在栈上编译就要定好尺寸。运行时不能随便变大。生命周期绑定函数调用。函数 return栈内存立刻销毁。如果你希望函数返回之后这块内存数据还继续存在栈做不到。函数返回栈帧弹走数据直接销毁。栈空间容量有限不能存超大块数据会栈溢出 stack overflow。举例函数里面定义$arr []局部变量函数结束栈上局部变量直接回收。2、堆heap应对运行时才确定的内存需求堆也叫动态内存。malloc/ PHP new 对象都是向堆申请内存。堆产生的两大根因内存大小运行时才确定用户输入、读取数据库、网络拿到数据程序运行起来才知道到底要多大内存。编译的时候根本算不出需要多少空间。栈无法满足。内存生命周期不受函数约束我在A函数申请一块内存A函数执行结束这块内存仍然要继续存在交给B函数继续使用。栈函数return就销毁实现不了这个需求。堆特点内存手动管理C语言需要手动freePHP有GC垃圾回收。申请不会自动释放。空间巨大使用虚拟内存可以很大。分配开销比栈大需要内核、内存管理器找空闲内存块。生命周期完全由代码控制和函数调用栈无关。代价忘记释放内存泄漏重复释放、野指针程序崩溃。PHP屏蔽了手动free依靠引用计数垃圾回收回收堆内存但底层依然是堆。PHP对象、数组本质全部存放在堆内存变量符号在栈真正的数据本体在堆。3、对比总结栈 Stack堆 Heap分配时机编译期确定大小运行时动态确定大小生命周期函数调用绑定函数返回自动销毁代码手动控制可跨函数存活管理方式自动移动栈指针显式申请垃圾回收 / free释放空间大小很小MB级别很大虚拟内存支撑速度极快相对慢典型问题栈溢出内存泄漏、野指针4、通俗类比栈临时工作台你调用一个函数就在工作台上摆工具局部变量。函数干完活离开工作台直接清空。工作台面积有限。工具不能带走人一走东西全部清空。堆仓库需要多大仓库空间干活的时候才知道。申请一块仓库用完可以交给别人继续使用用完必须归还仓库。仓库空间很大如果你不归还仓库空间就被占住造成浪费内存泄漏。5、回到PHP视角理解functiontest(){$user[namezhangsan];// $user这个变量符号在栈真正数组数据存在堆return$user;}$utest();函数test()执行完毕栈帧销毁局部变量符号KaTeX parse error: Cant use function \( in math mode at position 5: user\̲(̲user消失但是数组真实数据…u继续使用。如果只有栈函数return数组直接销毁无法返回数据。这就是堆存在的现实意义。根因来源于两种内存生命周期模式。栈用来存放函数局部变量大小编译期基本确定函数执行完自动释放速度快。但是栈空间有限内存生命周期绑定函数调用函数返回内存就销毁。很多场景内存大小、存活时间只有运行时才清楚并且希望函数结束后数据依然存活栈满足不了于是出现堆。堆是动态内存空间大生命周期由程序控制可以跨函数使用代价是需要内存回收处理处理不当会内存泄漏。PHP的对象、数组底层数据都存放在堆。
返回列表