下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922
论坛 >移动开发 >iOS 进阶—— iOS 内存管理(一)

iOS 进阶—— iOS 内存管理(一)

希尔瓦娜斯发布于 2017-09-15 09:44查看:925

     1 似乎每个人在学习 iOS 过程中都考虑过的问题

                alloc retain release delloc 做了什么?

                autoreleasepool 是怎样实现的?

                __unsafe_unretained 是什么?

                Block 是怎样实现的

                什么时候会引起循环引用,什么时候不会引起循环引用?

        所以我将在本篇博文中详细的从 ARC 解释到 iOS 的内存管理,以及 Block 相关的原理、源码。

     2 从 ARC 说起

        说 iOS 的内存管理,就不得不从 ARC(Automatic Reference Counting / 自动引用计数) 说起, ARC 是 WWDC2011 和 iOS5 引入的变化。ARC 是 LLVM 3.0 编译器的特性,用来自动管理内存。

        与 Java 中 GC 不同,ARC 是编译器特性,而不是基于运行时的,所以 ARC 其实是在编译阶段自动帮开发者插入了管理内存的代码,而不是实时监控与回收内存。

image.png

        ARC 的内存管理规则可以简述为:

                每个对象都有一个『被引用计数』

                对象被持有,『被引用计数』+1

                对象被放弃持有,『被引用计数』-1

                『引用计数』=0,释放对象


      3 你需要知道

        包含 NSObject 类的 Foundation 框架并没有公开

        Core Foundation 框架源代码,以及通过 NSObject 进行内存管理的部分源代码是公开的。

        GNUstep 是 Foundation 框架的互换框架

         GNUstep 也是 GNU 计划之一。将 Cocoa Objective-C 软件库以自由软件方式重新实现
         某种意义上,GNUstep 和 Foundation 框架的实现是相似的
         通过 GNUstep 的源码来分析 Foundation 的内存管理

     4 alloc retain release dealloc 的实现

      4.1 GNU – alloc

        查看 GNUStep 中的 alloc 函数。

        GNUstep/modules/core/base/Source/NSObject.m alloc:

image.png

        GNUstep/modules/core/base/Source/NSObject.m NSAllocateObject:

image.png


    NSAllocateObject 函数通过调用 NSZoneCalloc 函数来分配存放对象所需的空间,之后将该内存空间置为 nil,最后返回作为对象而使用的指针。

        我们将上面的代码做简化整理:

        GNUstep/modules/core/base/Source/NSObject.m alloc 简化版本:

image.png


        alloc 类方法用 struct obj_layout 中的 retained 整数来保存引用计数,并将其写入对象的内存头部,该对象内存块全部置为 0 后返回。

        一个对象的表示便如下图:

image.png

       4.2 GNU – retain

        GNUstep/modules/core/base/Source/NSObject.m retainCount:

image.png

        GNUstep/modules/core/base/Source/NSObject.m retain:

image.png

        以上代码中, NSIncrementExtraRefCount 方法首先写入了当 retained 变量超出最大值时发生异常的代码(因为 retained 是 NSUInteger 变量),然后进行 retain ++ 代码。

      4.3 GNU – release

        和 retain 相应的,release 方法做的就是 retain --

        GNUstep/modules/core/base/Source/NSObject.m release

image.png


      4.4 GNU – dealloc

        dealloc 将会对对象进行释放。

        GNUstep/modules/core/base/Source/NSObject.m dealloc:

image.png


      4.5 Apple 实现

        在 Xcode 中 设置 Debug -> Debug Workflow -> Always Show Disassenbly 打开。这样在打断点后,可以看到更详细的方法调用。

        通过在 NSObject 类的 alloc 等方法上设置断点追踪可以看到几个方法内部分别调用了:

        retainCount

            __CFdoExternRefOperation
            CFBasicHashGetCountOfKey

        retain

            __CFdoExternRefOperation
            CFBasicHashAddValue

        release

           __CFdoExternRefOperation
            CFBasicHashRemoveValue

        可以看到他们都调用了一个共同的 __CFdoExternRefOperation 方法。

        该方法从前缀可以看到是包含在 Core Foundation,在 CFRuntime.c 中可以找到,做简化后列出源码:

        CFRuntime.c __CFDoExternRefOperation:

image.png


        所以 __CFDoExternRefOperation 是针对不同的操作,进行具体的方法调用,如果 op 是 OPERATION_retain,就去掉用具体实现 retain 的方法。

        从 BasicHash 这样的方法名可以看出,其实引用计数表就是散列表。

        key 为 hash(对象的地址) value 为 引用计数。

        下图是 Apple 和 GNU 的实现对比:

image.png


收藏(0)0
查看评分情况

全部评分

此主贴暂时没有点赞评分

总计:0

回复分享

共有0条评论

    • 慧星的那一夜
    • MK
    • 药师
    • IT宅男
    • mr jack
    • YUI
    • Mr ken
    • cappuccino
    • 课课家技术团队1
    • 选择版块:

    • 标题:

    • 内容

    • 验证码:

    • 标题:

    • 内容

    • 选择版块:

    移动帖子x

    移动到: