Redian新闻
>
堆和栈它们的内涵有多深

堆和栈它们的内涵有多深

公众号新闻

前言

作为一名程序员,许多同学会把堆和栈这两个字,变成一个词放在一起,其实这是错误的。

堆(heap)

堆是一个内存空间,这个内存可以由程序员分配和释放,当然部分语言自带 GC( Garbage Collection 垃圾回收),部分堆内存可以由 GC 回收。这里千万要注意,这里说的「堆」数据结构 里面说的「堆」不是同一个概念,大家千万不要混淆。

堆是程序在运行的时候请求操作系统分配给自己内存。由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率相对栈来说略低。但是堆的优点在于,编译器不必知道要从堆里分配多少内存空间,也不必知道存储的数据要在堆里停留多长的时间,因此用堆保存数据时会得到更大的灵活性。所以为达到这种灵活性,在堆里分配存储空间时会花相对更长的时间,这也是效率低于栈的原因。

栈(stack)

栈是由编译器自动分配和释放的,存放函数的参数值,局部变量的值等。也请注意,这里说的「栈」不是 数据结构 中的「栈」,大家千万不要混淆。这里请注意,栈是由由系统自动分配。

栈的优势是存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
说的再通俗点  
使用栈就像我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就像是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

实际应用

看完上面一段文字,大多数同学自然就懂了,而不懂的,还是一脸懵。这些东西我知道了有什么实际意义?比如栈既然是系统分配和释放,我干预不了,我知道它干什么?那这里就以编程语言 C#(C Sharp)来举例说明。也可以看相应的 👉 LeetBook
堆、栈的实际意义

堆、栈,算是相对底层一些的内容,大部分的语言其实这部分内容都是类似的。如果你不会 C# 语言也能看懂~。

我们都知道,C# 的数据类型有两大类型 —— 值类型引用类型。大致结构如下图:

值类型我们看到包含内置值类型、用户定义的值类型和枚举。枚举就不用说了,内置值类型指的是 int、float、bool、double 等等。

用户定义的值类型指的就是 struct。引用类型大概我们学 C 语言的时候学到的指针类型(C# 做了封装,所以我们看不到 int * 这类的代码,当然可以使用 unsafe 关键字,这里就不多赘述)、接口类型、用户自定义的类(class),数组等。
类型的含义
这里为什么要解释这两个大的类型?首先是因为值类型是放在栈上的,值类型变量声明后,不管是否已经赋值,编译器为其分配内存。然而引用类型当声明一个变量时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,这时会分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。

通俗一点,堆上存放的是我们声明出来的实例对象,当我们需要访问这个实例对象时,我们找到它的方法是先找到变量对应在栈上的内存,然后通过栈上存放的数据,我们才能找到其真正的实例在堆的任意位置。


代码

class A{    public A(int x){        X = x;    }
public int X { get; set; }}
static void Main(string[] args){ int m = 1; int n = m; m = 2; Console.WriteLine($"m = {m}, n = {n}");
A a = new A(1); var b = a; a.X = 2; Console.WriteLine($"a.X = {a.X}, b.X = {b.X}");}

我们会发现输出结果是

m = 2, n = 1a.X = 2, b.X = 2

我们发现 m 和 n 的值是分别独立的,而 a 和 b 修改其中一个会修改两个值。这是因为 m 和 n 都是分配在栈上的,而 a 和 b 虽然也是在栈上,但是其只是存储的堆上的一个地址索引,我们不管通过 a 还是 b 索引到的堆上的内存都是同一份。

我们再来看值类型和引用类型,在栈上的数据访问快,在堆上的数据访问相对慢,因此,当我们开发过程中,通过需求,比如底层的一些不变数据,完全可以有 struct 来实现,因为其不会为 null,符合值类型的要求,而且我们经常访问会更快一些。

我们看上图发现,值类型和引用类型都是继承自 Object ,也就是说:
Object a = 1;int b = (int)a;

这两个都是合法语句。但是这里面隐藏了一个非常常见的一个现象,那就是装箱和拆箱。

  • 什么是拆装箱?
装箱实际上是将值类型转换为引用类型,而拆箱是将引用类型转换为值类型。再透彻点,实际上装箱拆箱就是栈内存和堆内存的来回拷贝和赋值,这不仅仅浪费性能,而且还会造成没必要的 GC。因此,能避免 “装箱”、“拆箱” 操作的就尽量避免。除上面所说的这些数据类型,还有一个写代码必不可少的,那就是函数。
函数是如何调用的?实际上函数调用的参数是通过栈空间来传递,在调用过程中会占用线程的栈资源。

当我们使用递归算法时,每次虽然调用的是同一个函数,但是会在栈中占用一个空间,只有走到最后的结束点后函数才能依次退出,而未到达最后的结束点之前,占用的栈空间一直没有释放。因此如果递归调用次数过多,就可能导致占用的栈资源超过线程的最大值,从而导致栈溢出,这也是为什么一定要尽量少用递归的原因。


写在最后

上面说了很多,侧面说明了堆、栈的应用的优缺点,平时应用中需要更加了解我们写的代码都“干了什么”,这样才有可能写出更高效、更可靠的代码。对于一名程序员来说,不管未来编程语言发展的多么容易上手,一定不要忘了学习计算机的基础知识,哪怕是先学会了编程再返回来补习这些知识。祝大家工作顺利、评论留言少 BUG !点赞转发不脱发!


BY / 

本文作者:力扣

编辑&版式:Janson

声明:本文归“力扣”版权所有,如需转载请联系。


点个在看,少个 bug

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
虚假实习、PUA学生,装Gay……留学生找工作的坑有多深?你想象不到!马克谈天下(330) 聊聊公投那些事中金:中国式现代化的经济内涵 ——二十大报告简评上海、杭州先后发现XBB、BQ.1毒株,Cell论文揭示它们的免疫逃逸有多强人间宝藏到底能挖多深?这台机器亮了!丨 图图科幻消失的童年:我们的孩子,正在被它们“洗脑”盘点美国的“南方哈佛”的5所大学,它们的热门申请专业是什么?小毕娶了日本媳妇(二)深度解析,唐僧肉长生不老的本质与内涵奈雪牵手乐乐茶,解决不了它们的模式难题文科老留,再也不用担心被解雇了 (中)越来越贵的羽绒服,水有多深?我走访了很多深圳中小学,几乎每间教室都这样:大白天开着灯,然后拉着窗帘国海研究 | 我们的行业,我们的2022,我们的2023!你的内裤该“换季”了,试了32条才找到「不夹臀」的内裤,暖呼呼,提臀超性感大佬们的内部讲话,左边是大棒,右边是胡萝卜一充再充、终端不兼容,电视会员的陷阱有多深?张艺兴内涵前队友?沈腾瘦身成功大变样?如菊姐厌烦老公?糊咖男星很狂妄?白云升起的地方:尼加拉大瀑布你想不到水有多深人到中年-对财富承担责任【宏观经济】中国式现代化的精神内涵与战略部署—学习二十大报告精神创新一习话丨“实现高质量发展,必须实现依靠创新驱动的内涵型增长”清朝康乾盛世时期,其他国家在做什么?它们的发展如何?羽绒服新国标不看“含绒”看“绒子”,它们的区别在哪?奥迪新海报,内涵了一把宝马、奔驰!在新加坡到处都是猫,它们的耳朵都少了一角,你知道是为什么吗?不要低估它们的下作奥迪发了一张内涵海报,奔驰宝马至今不敢回应?普京这次特殊的会见,暴露出很多深层次的问题马化腾谈PCG内部改革不客气:活都活不下去,周末还休闲打球,留给它们的时间不多了它们的搞笑喜感瞬间,承包了我这一年的笑点香蕉,怎么成了全球流行的内涵符号?实木沙发实为水泥,家具市场的“水”到底有多深ML如何做科学发现?牛津大学268页博士论文详述科学机器学习内涵
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。