OC基础知识梳理 - Stack 和 Heap

一、C 程序的内存结构

因为 Objetive-C 是基于 C 之上的,为了能充分了解 OC 中的 Stack 和 Heap, 让我们先看看在一个 C 程序中,内存是如何分布的。

内存结构 - 图片来源:

如图所示,一个 C 程序的内存分布共有5个区:

  1. code/代码区: 代码区包含程序编译后的所有方法,包括系统的方法。通常以机器码的形式储存。代码区通常是只读的,并且内存大小是固定的。代码区处于内存的地位,以防止 Stack 与 Heap 覆盖了代码区。

  2. initialized data/全局初始化数据区/静态数据区: 全局初始化数据区可简称为数据区,数据区只初始化一次,用来保存全局与静态变量。进一步划分可划分为 只读数据区 与 读写数据区,例如,当创建 char s[] = "Hello"; 时,字符串的指针 s 会储存于读写数据区,而 "Hello" 字符串会储存于只读数据区。

  3. uninitialized data(bss)/未初始化数据区: 未初始化数据区用来储存没有赋值的全局与静态变量。例如,global int j; 与 static int i; 都会储存于这个区。

  4. stack/栈: 栈是一片动态的内存区域,从内存的高位往地位扩张,一般与堆的扩张方向相反。类似于栈的数据结构,具有LIFO的�特性。每当一个方法被调用时,一个 stack frame/栈帧 就会被压入栈中,栈帧 里有所调用方法的返回地址、参数与局部变量等相关信息。当当前方法返回时,相应的栈帧会被销毁。栈内的内存管理都是由系统进行调用和销毁的,所以程序员不需要进行操作。

  5. heap/堆: 一般处于内存的低位往高位扩张(与的扩张方向相反)。堆是动态内存区,内存由程序员进行分配管理。开发时可使用 malloc(), calloc(), realloc() 进行内存的分配,并使用 free() 进行内存的销毁。

Stack 和 Heap 的主要区别

  1. 访问速度:stack 的访问速度比 heap 快
  2. 内存限制:stack 一般有内存大小限制,而heap没有,除非是硬件的性能限制
  3. 作用域:stack 中的变量只会在方法调用时存在,当方法返回时,变量会被销毁。而 heap 中的变量是全局的,能一直访问,直至该内存块被程序员手动销毁。
  4. 内存碎片化:Stack 上的内存由 CPU 管理,不会出现内存碎片化的情况。而处于 Heap 上的内存不能保证能充分利用,可能会出现内存碎片化

何时使用 Stack 和 Heap

  1. 本地变量首选使用 Stack, 因为读写更快,而且内存由系统自动管理。
  2. 当需要使用占用内存大的数据结构,使用 Heap。如 array, set 等, 因为 Stack 的内存大小有限制。当使用的内存超出 Stack 可使用范围内,便会出现 StackOverflow.
  3. 当需要一个作用域大于当前方法作用域的变量时,使用 Heap。例如,一个方法需要返回一个数组。该数组必须创建于 Heap,因为 Stack 内的局部变量会在返回时被销毁,返回 Stack 上的变量会在编译时报错。
  4. 当一个变量的内存大小不确定时,使用 Heap。如 动态数组。同理,因为 stack 上的内存限制,当变量的内存大小不确定时,最好选用 Heap。

二、Objective-C 中的 Stack 与 Heap

在 Objective-C 中,NSObject 包含了一个类指针 Class *isa, 里面指向对象类的属性列表、方法列表等信息,得益于 Objective-C 强大的 runtime,运行时可以再对类添加方法、添加属性。

换句话说,NSObject 类在编译时是无法确定其占用内存大小的,因为在运行时可以再对类进行修改,所以理所当然的,所有继承于 NSObject 的类,在新建对象时都是分配在 Heap 上的。而在 Objective-C 中,所有的类都是继承于 NSObject,所以我们新建的对象都处于 Heap 上,必须使用引用计数进行内存管理。

Block 的内存管理

Objetive-C 中 Block 的内存管理与其他的类稍有不同,以下是三个不同类型的 Block 以及他们的使用场景,根据不同的使用情况,程序编译时会创建不一样类型的 Block:(这里讨论的都是使用 ARC 时的情况,使用 MRC 的话会稍有不同)

  • NSConcreateGlobalBlock: 内存分配在静态数据区,当 Block 不需要访问访问外部变量时。
id block = ^(){};
NSLog(@"This is a global block: %@", block);
// This is a global block: <__NSGlobalBlock__: 0x1054480a0>
  • NSConcreateStackBlock: 内存分配在 Stack,当 Block 引用外部变量,而且没有 owner 时,即没有指针引用当前 Block。
int b = 100;
NSLog(@"This is a stack block: %@", ^(){
        int a = b;
    });
// This is a stack block: : <__NSStackBlock__: 0x7ffeea7b68d8>
  • NSConcreateMallocBlock: 内存分配在 Heap,当 Block 引用外部变量,并被引用或作为返回值时
int b = 100;
id block = ^(){
        int a = b;
    };
NSLog(@"This is a Malloc Block being referenced: %@", block);
// This is a Malloc Block being referenced: <__NSMallocBlock__: 0x600003a193e0>
- (void(^)(void))block
{
    int b = 100;
    return ^(){
        int a = b;
    };
}
NSLog(@"This is a Malloc Block being returned: %@", [self block]);
// This is a Malloc Block being returned: <__NSMallocBlock__: 0x600003a19140>

参考资料:

Memory Layout of C Programs
C语言内存分配-通俗理解
What's the difference between a stack and a heap?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容