Swift 栈和堆的理解

Posted

技术标签:

【中文标题】Swift 栈和堆的理解【英文标题】:Swift stack and heap understanding 【发布时间】:2015-02-11 00:50:33 【问题描述】:

我想快速了解堆栈和堆中存储的内容。我有一个粗略的估计: 您打印的所有内容和内存地址都不是值,而是存储在堆栈中,而作为值打印出来的内容,则在堆上,基本上根据值和引用类型。我完全错了吗?或者,您能否提供堆栈/堆的可视化表示?

【问题讨论】:

本演示文稿解释了 Swift 对堆和堆栈的一些使用:realm.io/news/andy-matuschak-controlling-complexity。简而言之,您不能像在 C 中那样假设值或引用最终会出现在堆上还是堆栈上。 【参考方案1】:

正如@Juul 所说,引用类型存储在堆中,值存储在堆栈中。

解释如下:

堆栈和堆

堆栈用于静态内存分配,堆用于动态内存分配,两者都存储在计算机的 RAM 中。

分配在栈上的变量直接存储到内存中,访问这块内存非常快,它的分配是在程序编译时确定的。当一个函数或方法调用另一个函数,而另一个函数又调用另一个函数等时,所有这些函数的执行将保持挂起,直到最后一个函数返回其值。堆栈始终以 LIFO 顺序保留,最近保留的块始终是下一个要释放的块。这使得跟踪堆栈变得非常简单。从堆栈中释放一个块只不过是调整一个指针。

在堆上分配的变量在运行时分配了它们的内存,访问这块内存有点慢,但堆大小只受虚拟内存大小的限制。堆的元素彼此之间没有依赖关系,并且总是可以随时随机访问。您可以随时分配块并随时释放它。这使得在任何给定时间跟踪堆的哪些部分已分配或空闲变得更加复杂。

对于转义闭包: 需要记住的一个重要注意事项是,如果存储在堆栈中的值在闭包中被捕获,则该值将被复制到堆中,以便在执行闭包时它仍然可用。

更多参考:http://net-informations.com/faq/net/stack-heap.htm

【讨论】:

要记住的重要一点是,如果存储在堆栈中的值在闭包中被捕获,该值将被移动到堆中,以便在闭包时它仍然可用执行。 @OleksandrKruk 这仅适用于转义闭包,因为只有那些可以稍后执行。 @Cristik 是真的 :),根据我的经验,它们中的大多数都在逃避,因为大量的闭包用于委托/异步请求,这就是为什么我提到它作为要记住的事情. @Cristik 感谢您的评论我更新了我的答案 因为你的大部分答案都是从这里复制的 net-informations.com/faq/net/stack-heap.htm 最好将其链接为参考。【参考方案2】:

类(引用类型)在堆中分配,值类型(如 Struct、String、Int、Bool 等)位于堆栈中。更详细的答案见本主题:Why Choose Struct Over Class?

【讨论】:

这不再是真的。当 Swift 可以证明值不会逃逸时,它可以优化一些分配以使它们成为堆栈分配。值与引用类型是概念上的区别,它不取决于分配值的位置。 @russbishop 感谢您的澄清。有没有关于你提到的优化的更多解释的网络链接? @russbishop 肯定会感谢带有解释的链接 这种优化称为“堆栈提升”。我在网上找不到任何概述其行为的文章,但如果您好奇,可以查阅 Swift 源代码。【参考方案3】:

堆栈与堆

Stack 是线程的一部分。它由 LIFO 顺序的方法(函数)帧组成。方法框架包含局部变量。实际上它是您在调试或分析错误[About] 时看到的方法堆栈跟踪。创建新的值副本 - 它可以是reference type 地址的副本或value type 的副本(写入时复制机制)。线程安全[About]

Heap ARC[About] 发挥作用的内存的另一部分。在这里分配内存需要更多的时间(找到合适的地方并以同步方式分配)。参考的新副本已创建

这些概念与[JVM illustration]相同

Xcode 建议您使用 Debug Memory Graph 的下一个变体

*要查看 Backtrace,请使用 Malloc Stack Logging

[Value vs Reference type][Class vs Struct]

【讨论】:

以上是关于Swift 栈和堆的理解的主要内容,如果未能解决你的问题,请参考以下文章

栈和队列的区别,栈和堆的区别

栈和堆的区别

变量的存储 -- 栈和堆的区别

C++中栈和堆的地址

值类型和引用类型,栈和堆的含义

js栈和堆的区别