美文网首页
认识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之对象方法内存

    一、这里先看结构体和类的方法区别 先看看一个简单的结构体,可以打开断点调试,发现其调用方法的汇编非常简单 call...

  • Swift

    lldb查看swift对象内存结构的方法fr v -R foo

  • 访问控制,内存管理

    swift系列课程 访问控制 扩展 将方法赋值给var\let sssimage.png 内存管理

  • Swift vs. Kotlin 漫谈系列之接口

    Swift vs. Kotlin 漫谈系列之接口 Swift vs. Kotlin 漫谈系列之接口

  • swift-对象创建底层浅析

    1. swift对象的创建流程 通过swift_slowAlloc分配内存,并进行内存字节对齐 通过new + H...

  • 认识Swift系列13之对象初始化

    Swift中初始化器: 指定初始化器(designated initializer) 便捷初始化器(conveni...

  • Swift学习-进阶02

    swift对象本质,一个swift的对象默认占用16字节大小,在内存中的结构: swift类结构: 属性 存储属性...

  • Swift5.0的Runtime机制浅析

    导读:你想知道Swift内部对象是如何创建的吗?方法以及函数调用又是如何实现的吗?成员变量的访问以及对象内存布局又...

  • Android 内存泄漏

    内存泄漏的原因 常见的内存泄漏与解决方法 检测内存泄漏 认识内存泄漏 根本原因就是当一个对象理应被回收的时候,因为...

  • 面试驱动技术之 - isa && 元类 &

    面试驱动技术之 - 带着面试题来找答案 一个NSObject 对象,占用多少内存 对象方法 与 类方法的存放在哪 ...

网友评论

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

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