• Block的详细介绍


    关于block的介绍


    ios中的内存空间分级

    1. 栈区
      • 存放函数参数值、局部变量、函数返回地址等,函数跳转跳转时现场保护(寄存器),这些系统都会帮我们自动实现,无需我们干预。 所以大量的局部变量,深递归,函数循环调用都可能耗尽栈内存而造成程序崩溃 。我们每次调用函数,都会执行压栈操作(在XCode的左侧面板会看到一堆的函数调用栈)。
      • 特点是存取效率高,存取结构连续,但是空间很小,有系统自行分配以及管理栈的地址空间。
      • 一种先进后出,压栈出栈更像是一个容器。
    2. 堆区
      • 平时涉及到内存管理基本上出自于这个区域。由malloc、alloc、copy(深复制)、new等方法触发的效果就是在堆区进行内存分配。
      • 堆是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
      • 数据呈现一般是树状的,类似链表式
    3. 常量区
      • 存放常量,由系统释放以及分配。
    4. 静态区
      • 该区域其实细分为数据区以及BSS区(BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。BSS节不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效地清零。BSS节在应用程序的二进制映象文件中并不存在。)。数据区存放已经初始化好的静态变量以及全局变量,而BSS区则存放还没有初始化好的静态变量以及全局变量,由系统负责释放以及分配。
      • 是存放开辟过和未开辟过静态变量和全局变量的地方。
    5. 文本区
      • 放置已经编译成二进制机器语言的代码文本。会依照应用的运行情况而依次调用。类似游戏规则。

    block的分级

    1. 全局区的Block__NSGlobalBlock__
      • 当我们声明一个block时,如果这个block没有捕获外部的变量,那么这个block就位于全局区,此时对NSGlobalBlockretain、copy、release操作都无效。
    2. 栈区的Block__NSStackBlock__
      • 平时编程的时候很少遇到位于栈区的block,为什么呢?因为在ARC环境下,当我们声明并且定义了一个block,并且没有为Block添加额外的修饰符(默认是__strong修饰符),如果该Block捕获了外部的变量,实质上是有一个从__NSStackBlock__转变到__NSMallocBlock__的过程,只不过是系统帮我们完成了copy操作,将栈区的block迁移到堆区,延长了Block的生命周期。对于栈区block而言,栈block在当函数退出的时候,该空间就会被回收。什么时候在ARC的环境下出现__NSStackBlock__呢?如果我们在声明一个block的时候,使用了__weak或者__unsafe__unretained的修饰符,那么系统就不会为我们做copy的操作,不会将其迁移到堆区。
    3. 堆区的Block__NSMallocBlock__
      • 我们需要手动调用copy方法才可以将block迁移到堆区,而在ARC环境下,__strong修饰的(默认)block只要捕获了外部变量就会位于堆区,NSMallocBlock支持retain、release,会对其引用计数+1或 -1。

    __block修饰符

    1. 应该是考虑到了block的特殊性,block也属于“函数”的范畴,变量进入block,实际就是已经改变了作用域。在几个作用域之间进行切换时,如果不加上这样的限制,变量的可维护性将大大降低。又比如我想在block内声明了一个与外部同名的变量,此时是允许呢还是不允许呢?只有加上了这样的限制,这样的情景才能实现。于是栈区变成了红灯区,堆区变成了绿灯区。
    2. 对于捕获的普通的外部变量,block并不能作出修改。我们要改变外部变量的内存地址,也就是使用__block修饰符将外部变量在栈中指针的内存地址,迁移到堆区中来。
    3. __block修饰符的根本操作就是改变外部变量的内存地址,并不是简单地使得写操作生效。
    4. 那么什么情况下不需要__block作为修饰符。将block捕获的外部变量使用static修饰或者将外部变量声明为全局变量,那么block是可以直接修改该外部变量的,因为全局变量或静态变量在内存中的地址是固定的(存放于静态区),Block在读取该变量值的时候是直接从其所在内存读出,获取到的是最新值,而不是在定义时copy的常量。
    5. 某些图方便直接用copy修饰生命block。直接拿到一个堆区block。里面捕获变量的过程中就不需要修饰符来让OS帮忙拷贝直接可以使用了。但是原理一定要清晰,一个失控的机制远比可控的机制恐怖的多。这里需要警醒。

    循环引用的原理

    1. 循环引用是因为出现了资源的持有闭环。OS的判定机制会认为这个空间仍在使用,所以相关联的三方资源一个都不会释放;
    2. __weak的弱引用替换掉__strong的时候会打破闭环释放三方资源。但是随之到来的是unsafe。这是需要注意的地方;

    block究竟是个什么东西

    • 由上面种种,我们可以推测出。block算是一个另类的函数。是将代码段闭包抽象为一种对象调用的手段。

    多线程下的block

    1. 存不存在资源抢夺?会出现哪些问题?如果有该怎么避免?
  • 相关阅读:
    App.config使用ASP.NET Web Project的Transformation模式编译方式
    简易扩展Visual Studio UnitTesting支持TestMethodCase
    Microsoft Unity ---- 系列文章
    Reflector 7.0.0.420 注册破解版
    在Vue前端界面中,几种数据表格的展示处理,以及表格编辑录入处理操作。
    基于Vue的工作流项目模块中,使用动态组件的方式统一呈现不同表单数据的处理方式
    在Vue前端项目中,附件展示的自定义组件开发
    在Vue&Element前端项目中,对于字典列表的显示处理
    kestrel对接elasticsearch踩坑记
    华为智慧安平解决方案——安防视频监控是核心
  • 原文地址:https://www.cnblogs.com/fuunnyy/p/9965216.html
Copyright © 2020-2023  润新知