面试之概念篇

iOS 堆和栈

2019-03-26  本文已影响0人  liboxiang

heap(堆)和stack(栈)是内存管理的两个重要概念。在这里我们指的不是数据结构上面的堆与栈,在这里指的是内存的分配区域。

了解堆、栈,有助于更好地理解参数传递,多态,线程,异常和垃圾收集。

stacknheap.png

栈(堆栈/stack)

stack的空间由操作系统进行分配,分配发生在连续的内存块上,向低内存地址堆扩展的

在现代操作系统中,一个线程会分配一个stack,当线程退出堆栈时回收. 当一个函数被调用,一个stack frame(栈帧)就会被压到stack里。里面包含这个函数涉及的参数,局部变量,返回地址等相关信息。当函数返回后,这个栈帧就会被销毁。而这一切都是自动的,由系统帮我们进行分配与销毁。对于程序员是透明的,我们不需要手动调度。

堆(heap)

heap的空间需要手动分配,堆是向高地址扩展的数据结构

heap与动态内存分配相关,内存可以随时在堆中分配和销毁。我们需要明确请求内存分配与内存销毁。 简单来说,就是malloc与free。应用程序通常只有一个堆。

内存不足问题更可能发生在堆栈中,而堆内存中的主要问题是碎片和内存泄漏问题

栈 VS 堆

堆栈更快,因为访问模式使得从中分配和释放内存变得微不足道(指针/整数简单地递增或递减),而堆在分配或释放中涉及更复杂的簿记。此外,堆栈中的每个字节都经常被频繁地重用,这意味着它往往被映射到处理器的缓存,使其非常快。堆的另一个性能损失是堆(主要是全局资源)通常必须是多线程安全的,即每个分配和释放需要 - 通常 - 与程序中的“所有”其他堆访问同步。

Objective-C中的Stack和Heap

首先所有的Objective-C对象都是分配在heap的。 在OC最典型的内存分配与初始化就是这样的。

NSObject *obj = [[NSObject alloc] init];

一个对象在alloc的时候,就在Heap分配了内存空间。

stack对象通常有速度的优势,而且不会发生内存泄露问题。那么为什么OC的对象都是分配在heap的呢? 原因在于:

  • stack对象的生命周期所导致的问题。例如一旦函数返回,则所在的stack frame就会被摧毁。那么此时返回的对象也会一并摧毁。这个时候我们去retain这个对象是无效的。因为整个stack frame都已经被摧毁了。简单而言,就是stack对象的生命周期不适合Objective-C的引用计数内存管理方法。
  • stack对象不够灵活,不具备足够的扩展性。创建时长度已经是固定的,而stack对象的拥有者也就是所在的stack frame

关于Block

为什么block需要使用copy修饰符?

block在创建时是stack对象,如果我们需要在离开当前函数仍能够使用我们创建的block。我们就需要把它拷贝到堆上以便进行以引用计数为基础的内存管理。

最终得到的答案是这与block对象在创建时是stack对象有关。
所以,其实Objective-C是有它的Stack object的。是的,那就是block.

在Objective-C语言中,一共有3种类型的block:

  • _NSConcreteGlobalBlock 全局的静态block,不会访问任何外部变量。
  • _NSConcreteStackBlock 保存在栈中的block,当函数返回时会被销毁。
  • _NSConcreteMallocBlock 保存在堆中的block,当引用计数为0时会被销毁。

这里我们主要基于内存管理的角度对它们进行分类。

ARC

在ARC情况下,创建的block仍然是NSConcreteStackBlock类型,只不过当block被引用或返回时,ARC帮助我们完成了copy和内存管理的工作。

上一篇 下一篇

猜你喜欢

热点阅读