不再是指针的 isa
- 在 iOS arm64 的架构中,属于 Objective-C 对象的 isa 空间不再是一个指针。
如果它已经不再是一个指针,它是什么?
- 一些位仍旧编码指向对象的类。但是 OS X 和 iOS 实际上都不会使用所有 64 位的虚拟地址空间。Objective-C 运行时会使用这些额外的位去存储每个对象数据就像它的引用计数和是否它已经被弱引用。
为什么要改变它?
- 性能。重新利用这些限制的位来提高速度并且降低内存。在 iOS7上的重点是优化 retain/release 和 alloc/dealloc。
这对于代码来说意味着什么?
- 不直接调用 obj->isa 来读取。编译器将会报错。使用如下两个方法来代替:
[obj class]
//或者
object_getClass(obj)
- 不直接使用 obj->isa 来设置,调用
object_setClass()
- 如果重写了
+allocWithZone:
方法,在初始化的时候对象的 isa 区域变为未加工的 isa 指针,如果这样做,将不会有额外的数据存储到这个 isa 区域中并且会降低像 retain/ release 这样的代码执行效率。
为了让这些优化有效,调用 object_setClass() 来代替直接设置 isa 区域为0.
如果重写了 retain/release 来实现一个自定义内联保留计数,考虑删除这段运行时已经支持的代码。
64位 iOS 模拟器现在不会使用空指针的 isa,在 arm64的设备真机上来测试代码。
这对于调试器来说意味着什么?
- 调试器知道了怎么样去从 isa 区域中解码类。在大多数情况下你应该没必要去检查它。
- 你可以在
OBJC_DISABLE_NONPOINTER_ISA=YES
变量环境下来运行代码去禁止所有无指针 isa 类。如果你的代码在这种设置下工作并且在移除之后失败了。你也许在某处错误的直接访问了 isa 区域。 - 如果你正在写一个类似调试器的工具, Objective-C 运行时输出了一些变量来帮助调试 isa 区域。objc_debug_isa_class_mask描述了那些位是类的指针:
(isa & class_mask) == class pointer
是类的指针,objc_debug_isa_magic_mask
和objc_debug_isa_magic_value
来帮助从另外一些有效的值中区分有效的 isa 区域。isa 区域中的 (isa & magic_mask) == magic_value 并不是初始化类的指针。这些变量在将来会改变所以不要在应用代码中使用它们。
下面是一些位的意思
位 | 名称 | 意义 |
---|---|---|
1 bit | indexed | 0 is raw isa, 1 is non-pointer isa. |
1 bit | has_assoc | 对象拥有或者曾经拥有一个相关的参考。对象没有关联的引用可以释放的更快。 |
1 bit | has_cxx_dtor | 对象有一个 C++或者 ARC 的析构函数。没有析构函数的对象可以被释放的更快 |
30 bit | shiftcls | 类指针的非零位 Class pointer's non-zero bits. |
9 bit | magic | 等于 0xd2。被调试器用来从没初始化的东西中区分真是的对象 |
1 bit | weakly_referenced | 对象正被或者曾经被一个自动释放的弱引用变量指向。没有被弱引用的对象能够释放的更快。 |
1 bit | deallocating | 对象正在被释放 |
1 bit | has_sidetable_rc | 对象引用计数过大无法被 store inline |
19 bit | extra_rc | 对象的引用计数是extra_rc 值+1(举例,如果 extra_rc 是5,那么对象的真是引用计数是6) |