当前位置: 首页 > news >正文

白云区江夏附近做网站山东济南网站建设公司

白云区江夏附近做网站,山东济南网站建设公司,国家建设厅官方网站,建网站的网络公司目录 前言clang常用命令对象本质探索属性的本质对象的内存大小isa 指针探究 前言 OC 代码的底层实现都是 C/C代码#xff0c;OC 的对象都是基于 C/C 的数据结构实现的#xff0c;实际 OC 对象的本质就是结构体#xff0c;那到底是一个怎样的结构体呢#xff1f; clang常用… 目录 前言clang常用命令对象本质探索属性的本质对象的内存大小isa 指针探究 前言 OC 代码的底层实现都是 C/C代码OC 的对象都是基于 C/C 的数据结构实现的实际 OC 对象的本质就是结构体那到底是一个怎样的结构体呢 clang常用命令 clang是一个C语言、C、Objective-C语言的轻量级编译器是由Apple主导编写的 clang主要用于把源文件编译成底层文件比如把main.m 文件编译main.cpp、main.o或者可执行文件 我们可以在终端使用 clang 命令使OC代码转换成 C 代码 # 将 main.m 转换成 main.cpp 文件 clang -rewrite-objc main.m -o main.cpp打开此 main.cpp 文件共有 6 万多行代码 实际上不同平台支持的代码肯定是不一样的Windows 、 MacOS 、 iOS 等模拟器i386、 32bitarmv7、 64bitarm64等如果要指定平台比如在 arm64 下的 iOS 开发应在终端输入以下xcrun命令 # xcrun 命令基于 clang 进行了封装更好用# 真机编译 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp # 模拟器编译 xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp打开生成的 main-arm64.cpp 文件 行数缩减到了 2 万多行显然删减掉了冗余的代码 对象本质探索 将含有以下代码的 OC 文件转换成 Cpp 文件查看源码 OC 代码 interface Student : NSObject {publicint _no;int _age; }endCpp 代码 可以看到 Student 的定义IMPL即 implementation 实现的意思其实是 struct 也就是对象的本质是结构体 在此结构体的定义中有一个struct NSObject_IMPL结构体变量NSObject_IVARS表明 Student 继承于 NSObject 类子类的结构都包含父类的结构即包括 NSObject 的成员变量 在struct NSObject_IMPL的定义中可以看到只有isa一个成员其类型是 Class 我们再找到 Class 的定义 Class类型实际是一个objc_class类型的结构体指针我们还可以看到常用的id是objc_object结构体指针类型以及SEL是objc_selector函数的一个结构体指针 属性的本质 interface Person : NSObject property (nonatomic, assign)int height; // 自动生成实例变量、 setter/getter 方法 endimplementation Person end那么 setter/getter 方法在哪儿呢 创建出来的实例对象里面只存有实例变量方法不会放在实例对象里面而放在类对象中有关对象的分类因为方法是公用的方法的代码都是一样的 对象的内存大小 现在我们知道对象的本质其实就是一个结构体其内存大小与成员变量有关即isa其他成员变量。对象第 1 个成员变量就是isa结构体指针而结构体的地址就是第 1 个成员变量的地址即isa变量的地址 下面我们来看看一个NSObject对象占用多少内存NSObject只有一个成员变量也就是结构体指针变量isa 在 C/C 中结构体指针的内存占用大小通常取决于操作系统和计算机的体系结构与结构体本身的内容和大小无关。具体来说 在32位系统上指针通常占用4字节。在64位系统上指针通常占用8字节。 这个大小是指针自身的大小与指向的结构体中包含的数据类型或数量无关。指针的主要功能是存储内存地址所以它的大小应该与系统的地址长度一致 现在绝大多数计算机的都是 64 位所以 isa 变量占用 8 个字节也就是说 NSObject 对象占用 8 字节 为检验对象到底占用了多少内存引入以下两个库 #import objc/runtime.h #import malloc/malloc.h使用其中的 API NSObject* obj [NSObject alloc] init];// 下面两个函数的返回值都是size_tunsigned int所以占位符使用%zd NSLog(%zd, class_getInstanceSize([NSObject class]));//NSLog(%zd, malloc_size(CFBridgingRetain(obj))); NSLog(%zd, malloc_size((__bridge const void *)(obj))); //OC转C 要进行桥接__bridge运行结果 刚分析 NSObject 对象不应该占用 8 字节吗为什么第 2 个函数返回了 16 个字节 实际class_getInstanceSize()返回的是类实例对象的成员变量大小malloc_size()返回的是传入对象指针所指向的内存大小 下面来看看class_getInstanceSize()的实现 size_t class_getInstanceSize(Class cls) {if (!cls) return 0;return cls-alignedInstanceSize(); }查看最终的返回值如果字节数小于 16 通过这种方法返回的结果就是 16可见给 NSObject 分配了 16 个字节但真正利用起来的只有 8 个字节用来存放 isa 成员 注释也有提到 CoreFoundation框架要求所有对象至少占用 16 字节这种硬性规定返回的是内存对齐后的成员变量所占内存大小 所以一般不去过多地关注此函数而是通过malloc_size()准确的了解到对象占用内存大小 打断点通过 LLDB 查看内存分布 上面以十六进制的形式打出 LLDB 指令 print 、 p打印 po打印对象 —— 读取内存分布memory read/数量 格式 字节数 内存地址或x/数量 格式 字节数 内存地址 格式x是 16 进制f是浮点d是 10 进制字节大小b是byte 1字节w是word 4字节h是half word 2字节g是 giant word 8字节 —— 修改内存中的值memory write 内存地址 数值 通过 ViewMemory 实时查看内存数据 在此处输入内存地址 不论是通过 LLDB 还是 ViewMemory 都可以查看到标灰的位置就是obj对象的内存分布后面的都是其他不相关的内存分布 由于一个 16 进制位代表 4 个二进制位两个就代表 8 个二进制位1 个字节 71 20 32 E3 01 00 00 01 00 00 00 00 00 00 00 0016 个字节中实际就只有 8 个字节有数据成员变量这里指 isa 指针变量 0xe3322071 0x01000001 0x00000000这是地址分布怎么跟上面的顺序是相反的呢这里涉及到一个大小端的问题 大小端Endian是指数据在计算机内存中的存储方式具体来说是多字节数据的存储顺序问题。它主要涉及两种模式大端Big Endian和小端Little Endian。 大端 数据的高位字节存储在内存的低地址端低位字节存储在高地址端。也就是说数据的第一个字节最重要的字节存储在起始地址上。例如如果有一个32位的整数0x12345678存储在地址0x1000开始的位置上其存储顺序如下 0x1000: 0x120x1001: 0x340x1002: 0x560x1003: 0x78 大端模式直观地反映了数据在文档和其他数字表示中的顺序因此在阅读内存转储时容易理解。很多网络协议如TCP/IP采用大端模式来传输数据。 小端 数据的低位字节存储在内存的低地址端高位字节存储在高地址端。也就是说数据的最后一个字节最重要的字节存储在起始地址上。同样地如果有一个32位的整数0x12345678存储在地址0x1000开始的位置上其存储顺序如下 0x1000: 0x780x1001: 0x560x1002: 0x340x1003: 0x12 小端模式在某些类型的处理器如x86架构中使用因为它可以在处理器将数据加载到寄存器时减少字节重排的操作。 一些系统允许在大端和小端之间进行配置这种灵活性在处理多种硬件平台时特别有用。同时还存在一些更复杂的端模式例如双端模式或中间端模式这些通常用于特定的应用或硬件。 端序的理解对于开发者在处理字节级操作时至关重要尤其是在进行网络编程、读写文件以及在不同架构之间迁移代码时。不匹配的字节序会导致数据解释错误从而引发程序错误和数据损坏。因此开发者必须确保在这些操作中考虑到端序的因素。 总结 创建一个实例对象至少需要内存class_getInstanceSize对齐后实际分配内存malloc_size 最后以下例说明内存对齐 struct Person_IMPL {struct NSObject_IMPL NSOBJECT_IVARS; // 8int _age; // 4int _height; // 4int _no; // 4 }; // 和为20内存对齐交后24interface Person : NSObject {int _age;int _height;int _no; }endimplementation Personendvoid testAllocSize(void) {NSLog(%zd, sizeof(struct Person_IMPL)); //同class_getInstanceSize 24// sizeof 运算符关键字 不是一个函数 编译过程中就会查看传入的类型并识别数据类型字节大小 编译时就会确定为一个常数// 内存分配注意的地方Person* person [[Person alloc] init];NSLog(%zd %zd, class_getInstanceSize([Person class]), malloc_size((__bridge const void *)(person))); // 24 32// 操作系统在分配内存时也会有“内存对齐”所以 size 是 24返回 32NSLog(%zd, sizeof(person)); // 8 指的是person指针本身的大小 }isa 指针探究 之前在【iOS】alloc、init和new原理文章中提到了对象通过obj-initInstanceIsa初始化关联isa指针下面就来看看isa的结构如何通过它关联类 initInstanceIsa方法 inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor) {ASSERT(!cls-instancesRequireRawIsa());ASSERT(hasCxxDtor cls-hasCxxDtor());initIsa(cls, true, hasCxxDtor); }initIsa方法 inline void objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor) { ASSERT(!isTaggedPointer()); isa_t newisa(0); // isa初始化if (!nonpointer) { // 非nonpointer指针直接绑定clsnewisa.setClass(cls, this);} else {ASSERT(!DisableNonpointerIsa);ASSERT(!cls-instancesRequireRawIsa());#if SUPPORT_INDEXED_ISAASSERT(cls-classArrayIndex() 0);newisa.bits ISA_INDEX_MAGIC_VALUE;// isa.magic is part of ISA_MAGIC_VALUE// isa.nonpointer is part of ISA_MAGIC_VALUEnewisa.has_cxx_dtor hasCxxDtor;newisa.indexcls (uintptr_t)cls-classArrayIndex(); #elsenewisa.bits ISA_MAGIC_VALUE;// isa.magic is part of ISA_MAGIC_VALUE// isa.nonpointer is part of ISA_MAGIC_VALUE # if ISA_HAS_CXX_DTOR_BITnewisa.has_cxx_dtor hasCxxDtor; # endifnewisa.setClass(cls, this); #endif #if ISA_HAS_INLINE_RCnewisa.extra_rc 1; #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 dont want to hurt instantiationisa() newisa; }在initIsa方法中如果是非nonpointer类型指针则直接通过cls调setClass方法绑定否则现有一些位域bits赋值操作再调setClass方法绑定 我们可以看到方法内创建了一个 isa_t 类型的newisa实例 做了赋值操作newisa.bits ISA_MAGIC_VALUE;后返回了newisa 注释中写得很清晰news.bits初始化时候只设置了nonpointermagic两个部分其余部分都没有进行设置故值都为默认值0 该源码解释了上面初始化isa的两种方式 通过cls初始化非nonpointer存储着Class、Meta-Class对象的内存地址信息通过bits初始化nonpointer进行一系列的初始化操作 isa_t联合体 #include isa.hunion isa_t {isa_t() { }isa_t(uintptr_t value) : bits(value) { }uintptr_t bits;private:// Accessing the class requires custom ptrauth operations, so// force clients to go through setClass/getClass by making this// private.Class cls;public: #if defined(ISA_BITFIELD)struct {ISA_BITFIELD; // defined in isa.h};#if ISA_HAS_INLINE_RCbool isDeallocating() const {return extra_rc 0 has_sidetable_rc 0;}void setDeallocating() {extra_rc 0;has_sidetable_rc 0;} #endif // ISA_HAS_INLINE_RC#endifvoid setClass(Class cls, objc_object *obj);Class getClass(bool authenticated) const;Class getDecodedClass(bool authenticated) const; };isa_t是一个联合体类型其中的变量有bits、cls以及结构体里面的ISA_BITFIELD宏定义变量ISA_BITFIELD结构如下是按位域定义的 各个变量的内存分布图 各个变量的解释 nonpointer表示是否对 isa 指针开启指针优化0纯isa指针1不止是类对象地址isa中包含了类信息、对象的引用计数等has_assoc关联对象标志位0没有1存在has_cxx_dtor该对象是否有C或Objc的析构器如果有析构函数则需要做析构逻辑没有则可以更快的释放对象shiftcls存储类指针的值开启指针优化的情况下在ARM64架构中有33位来存储类指针值magic用于调试判断当前对象是真的对象还是未初始化的空间weakly_referenced标志对象是否被指向或曾经指向一个ARC的弱变量没有弱引用对象则可以更快地释放unused对象是否释放has_sidetable_rc当对象引用计数大于10时则需要借用该变量存储进位extra_rc对象的引用计数值实际上是引用计数减1例如引用计数是10那么extra_rc为9如果引用计数大于10则需要使用到has_sidetable_rc 总结 isa正是通过以上联合体中的变量信息将类关联起来isa指针分为nonpointer和非nonpointer类型非nonpointer类型0就是一个纯指针nonpointer类型1指针开启了指针优化指针优化的设计更好地利用isa的内存程序中有大量的对象针对isa的优化节省了大量内存
http://www.hkea.cn/news/14386723/

相关文章:

  • 微信显示个人网站深圳市小程序科技有限公司
  • 网站注册 英文专业做网文的网站好
  • 微网站与微信的关系只做财经的网站
  • 如何建立商城网站drupal vs wordpress
  • 06627网页制作和网站建设山西seo推广系统
  • 商务网站开发报告九寨沟城乡建设官方网站
  • 建站开发软件深圳网络公司推广平台
  • 如何看还在建设的网站现有的网站开发技术
  • 启蒙自助建站标书制作员这工作好吗
  • 莒县网站制作手机网站加百度商桥
  • 网站建设行业话术美工需要的网站
  • 美容医疗手机网站模板国内设计大神网站
  • 做自己的网站要多少钱做网站的公司叫什么软件
  • asp网站空间深圳机场最新消息今天
  • 做多语言网站不会翻译怎么办wordpress 1.0
  • 怎么用手机做网站服务器太原小程序制作电话
  • 网站为什么维护工程公司名称大全集最新免费
  • 千博医院网站模板百度在线咨询
  • tornado 网站开发做物流公司网站哪家好
  • 商城平台网站开发深圳创业邦使用什么网站模板
  • pc下载网站模板提高工作效率的方法
  • 网站建设项目规划书案例怎么自己制作属于自己的网站
  • 住房和城乡建设部网站进不去搭建网站服务器多少钱
  • 推荐专业的网站建设公司竞价排名深度解析
  • 网站宽度关键词排名怎么快速上去
  • 网站群建设管理规定如何自己开个网站平台
  • 新网站如何才做被百度收录网站如何进行优化
  • 网站源码是什么wordpress 面向对象
  • 设计素材网站好融资吗南宁建筑规划设计集团有限公司
  • 网站管理 官网wordpress+广告联盟