isa结构分析

简介: 在对象调用alloc, 之后调用的最后一个方法是obj->initInstanceIsa, 它的作用是将isa指针与我们的对象关联起来, 我们来分析一下isa指针.

在对象调用alloc, 之后调用的最后一个方法是obj->initInstanceIsa, 它的作用是将isa指针与我们的对象关联起来, 我们来分析一下isa指针.


我们这里先看下isa指针初始化的源码:


inline void   
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)   
{   
    ASSERT(!isTaggedPointer());   
    if (!nonpointer) {  
        isa = isa_t((uintptr_t)cls);  
    } else {  
        ASSERT(!DisableNonpointerIsa);  
        ASSERT(!cls->instancesRequireRawIsa());  
        isa_t newisa(0);  
#if SUPPORT_INDEXED_ISA  
        ASSERT(cls->classArrayIndex() > 0);  
        newisa.bits = ISA_INDEX_MAGIC_VALUE;  
        // isa.magic is part of ISA_MAGIC_VALUE  
        // isa.nonpointer is part of ISA_MAGIC_VALUE  
        newisa.has_cxx_dtor = hasCxxDtor;  
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();  
#else  
        newisa.bits = ISA_MAGIC_VALUE;  
        // isa.magic is part of ISA_MAGIC_VALUE  
        // isa.nonpointer is part of ISA_MAGIC_VALUE  
        newisa.has_cxx_dtor = hasCxxDtor;  
        newisa.shiftcls = (uintptr_t)cls >> 3;  
#endif  
        // This write must be performed in a single store in some cases  
        // (for example when realizing a class because other threads  
        // may simultaneously try to use the class).  
        // fixme use atomics here to guarantee single-store and to  
        // guarantee memory order w.r.t. the class index table  
        // ...but not too atomic because we don't want to hurt instantiation  
        isa = newisa;  
    }
}


其中通过宏ISA_INDEX_MAGIC_VALUE 我们可以找到isa的宏定义(此处只写出了x86_64)(还有arm64, armv7k or arm64_32)如下:


# elif __x86_64__  
#   define ISA_MASK        0x00007ffffffffff8ULL  
#   define ISA_MAGIC_MASK  0x001f800000000001ULL  
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL  
#   define ISA_BITFIELD                                                        \  
      uintptr_t nonpointer        : 1;                                         \  
      uintptr_t has_assoc         : 1;                                         \  
      uintptr_t has_cxx_dtor      : 1;                                         \  
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \  
      uintptr_t magic             : 6;                                         \  
      uintptr_t weakly_referenced : 1;                                         \  
      uintptr_t deallocating      : 1;                                         \  
      uintptr_t has_sidetable_rc  : 1;                                         \  
      uintptr_t extra_rc          : 8  
#   define RC_ONE   (1ULL<<56)  
#   define RC_HALF  (1ULL<<7)


我们都知道isa所占的内存大小为8字节, 一字节8位, 总共64位, 那么上面的代码的意思就是该isa指针所对应内存的顺序以及所占内存的大小. (本文在此并不做证明, 只是学习记录笔记)


  • nonpointer : 表示是否对isa指针开启指针优化 (0:纯isa指针  1:不止是类对象地址, isa中包含了类信息, 对象的引用计数等)
  • has_assoc : 关联对象标志位, 0没有, 1 存在
  • has_cxx_dtor :  该对象是否有C++或者Objc的析构器, 如果有析构函数, 则需要做析构逻辑, 如果没有, 则可以更快的释放对象.
  • shiftcls : 存储类指针的值, 开启指针优化的情况下, 在arm64架构中有33位用来存储类指针.
  • magic : 用于调试器判断当前对象是真的对象还是没有初始化的空间.
  • weakly_referenced : 对象是否被指向或者曾经指向一个ARC的若变量, 没有弱引用的对象可以更快释放.
  • deallocating : 标志对象是否正在释放内存.
  • has_sidetable_rc : 当对象引用计数大于10时, 则需要借用该变量存储进位.
  • extra_rc : 当表示该对象的引用计数值, 实际上是引用计数值减1, 例如, 如果对象的引用计数为10, 那么extra_rc为9. 如果引用计数大于10, 则需要使用到下面的has_sidetable_rc


记录一些编译指令


  • 用clang把目标文件编译成c++文件


clang -rewrite-objc main.m -o main.cpp


  • UIKit报错问题  (解决方法如下)


clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot / Applications/Xcode.app/Contents/Developer/Platforms/ iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m


  • xcode安装的时候顺带安装了xcrun命令,xcrun命令在clang的基础上进行了 一些封装,要更好用一些


xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp //模拟器
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main- arm64.cpp //手机



目录
相关文章
|
存储 C++
04-深入了解isa指针以及内部结构
04-深入了解isa指针以及内部结构
89 0
04-深入了解isa指针以及内部结构
|
存储 算法 程序员
深入理解程序的结构
深入理解程序的结构
190 0
|
算法
程序的三大结构
程序的三大结构是:顺序结构,选择结构,循环结构。
219 0
|
C语言 Windows
驱动开发:内核解析PE结构节表
在笔者上一篇文章`《驱动开发:内核解析PE结构导出表》`介绍了如何解析内存导出表结构,本章将继续延申实现解析PE结构的PE头,PE节表等数据,总体而言内核中解析PE结构与应用层没什么不同,在上一篇文章中`LyShark`封装实现了`KernelMapFile()`内存映射函数,在之后的章节中这个函数会被多次用到,为了减少代码冗余,后期文章只列出重要部分,读者可以自行去前面的文章中寻找特定的片段。
|
存储 Windows
驱动开发:内核解析PE结构导出表
在笔者的上一篇文章`《驱动开发:内核特征码扫描PE代码段》`中`LyShark`带大家通过封装好的`LySharkToolsUtilKernelBase`函数实现了动态获取内核模块基址,并通过`ntimage.h`头文件中提供的系列函数解析了指定内核模块的`PE节表`参数,本章将继续延申这个话题,实现对PE文件导出表的解析任务,导出表无法动态获取,解析导出表则必须读入内核模块到内存才可继续解析,所以我们需要分两步走,首先读入内核磁盘文件到内存,然后再通过`ntimage.h`中的系列函数解析即可。
|
编译器 C++
驱动开发:内核PE结构VA与FOA转换
本章将继续探索内核中解析PE文件的相关内容,PE文件中FOA与VA,RVA之间的转换也是很重要的,所谓的FOA是文件中的地址,VA则是内存装入后的虚拟地址,RVA是内存基址与当前地址的相对偏移,本章还是需要用到`《驱动开发:内核解析PE结构导出表》`中所封装的`KernelMapFile()`映射函数,在映射后对其PE格式进行相应的解析,并实现转换函数。
|
存储 缓存 固态存储
存储器层次结构
实际的软件开发过程中,常会遇到服务端请求响应时间长,吞吐率不够。 分析对应问题时,你肯定听过“主要瓶颈不在CPU,而在I/O”,存储很重要。
216 0
|
缓存 虚拟化 芯片
【操作系统】第三章:计算机体系结构及内存分层体系(Part1:计算机体系结构)
【操作系统】第三章:计算机体系结构及内存分层体系(Part1:计算机体系结构)
287 0
西门子S7-1200的调用结构
今天我们来介绍一下西门子S7-1200的调用结构。在西门子S7-1200中采用调用结构来描述用户程序中块的调用层级,调用结构提供了几个方面的信息,包括所用的块,对其它块的调用,各块之间的关系,每个块的数据要求以极块的状态等。
西门子S7-1200的调用结构

热门文章

最新文章