美文网首页
认识Swift系列12之对象方法内存

认识Swift系列12之对象方法内存

作者: Niuszeng | 来源:发表于2019-07-15 11:52 被阅读0次

    一、这里先看结构体和类的方法区别

    先看看一个简单的结构体,可以打开断点调试,发现其调用方法的汇编非常简单 callq 0x100001410

    struct Object {
        func eat() { }
    }
    var o = Object()
    o.eat() // 汇编:callq  0x100001410
    

    再看看一个用类来实现相同功能,发现其调用方法的汇编就变的复杂起来 callq *0x70(%rcx),经过进一步跟进断点,发现内部做了非常多的中转操作

    class Object {
        func eat() { }
    }
    var o = Object()
    o.eat() // 汇编:callq  *0x70(%rcx)
    

    实际上结构体和类的方法都存储在全局区,和全全局方法没有本质区别,只不过是编译器语法糖特性限制了我们的访问权限而已

    可以看出,结构体方法调用非常简单,编译期就决定了调用地址,直接call+地址,而类的方法调用则比价复杂,因为要考虑到继承多态等动态特性,调用地址并不能在编译其确定

    因此在设计时,如果某个类只是做一些简单的工作而不考虑复杂的事情时,优先选择结构体

    二、对象的内存布局

    对于一个对象,内存涉及到三块

    • 1.对象地址内存(可能在堆空间、栈空间、全局区,指向堆空间)
    • 2.对象本身内存(堆空间:分为3块)

      2.1 类信息地址(指向全局区)
      a.类的某些信息
      b.类的对象方法列表(一般按定义顺序存储)
      2.2 引用计数相关
      2.3 属性列表

    • 3.对象信息内存(全局区:分为2块)

      3.1 对象信息
      3.2 对象方法地址列表

    如Object类的一个对象

    class Object {
        var age = 10
        func eat() {
            print("\(type(of: self))-->\(#function)")
        }
        func run() {
            print("\(type(of: self))-->\(#function)")
        }
        func jump() {
            print("\(type(of: self))-->\(#function)")
        }
     }
    

    此处创建两个对象

    var obj1 = Object()
    var obj2 = Object()
    

    Swift中,其对象方法实现类似C++虚表方式,其内存布局如下

                                  虚表(类似C++)【全局区】
                                 ┏━━━━━━━━━━━━━━━━━━━━━━
                                 ┃ 类的某些信息
                                 ┗━━━━━━━━━━━━━━━━━━━━━━
                                 ┃ eat()方法地址
                                 ┗━━━━━━━━━━━━━━━━━━━━━━
     对象地址    对象内存【堆空间】   ┃ run()方法地址
     ┏━━━━━┓   ┏━━━━━━━━━━━━━┓   ┗━━━━━━━━━━━━━━━━━━━━━━
     ┃ obj1┃━━>┃ classInfo   ┃━━>┃ jump()方法地址
     ┗━━━━━┛   ┗━━━━━━━━━━━━━┛   ┗━━━━━━━━━━━━━━━━━━━━━━
               ┃ retainCount ┃       ↑
               ┗━━━━━━━━━━━━━┛       ┃
               ┃ var age     ┃       ┃
               ┗━━━━━━━━━━━━━┛       ┃
               ┃ var name    ┃       ┃
               ┗━━━━━━━━━━━━━┛       ┃
                                     ┃
                                     ┃
      对象地址    对象内存【堆空间】     ┃
      ┏━━━━━┓   ┏━━━━━━━━━━━━━┓      ┃
      ┃ obj2┃-->┃ classInfo   ┃━━━━━━┛
      ┗━━━━━┛   ┗━━━━━━━━━━━━━┛
                ┃ retainCount ┃
                ┗━━━━━━━━━━━━━┛
                ┃ var age     ┃
                ┗━━━━━━━━━━━━━┛
                ┃ var name    ┃
                ┗━━━━━━━━━━━━━┛
    

    综上所属

    • 1.所有同类型的对象共享一份虚表(方法列表)
    • 2.对象本身的存储属性和引用计数包含在对象内存中
    • 3.如果子类重写了父类的方法,则子类虚表中存储重写过的方法地址,如果子类没有重写,则子类虚表中会存储父类原本的方法地址

    相关文章

      网友评论

          本文标题:认识Swift系列12之对象方法内存

          本文链接:https://www.haomeiwen.com/subject/rsogkctx.html