OC对象的本质

探寻原因

一个NSObject对象占用多少内存?

对象的isa指针指向哪里?

OC的类信息存放在哪里?

转换指令:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件

揭开面纱

问题1:一个NSObject对象占用多少内存?


证明例子1:

对象的占用内存图

从上面的打印结果很奇怪,发现obj指针占有的内存是16个字节,然后class_getInstanceSize获取到的对象内存却只有8个字节,另外,从main-arm64.cpp源码里面,也可以看到structNSObject_IMPL {

Class isa;

}; 按道理指针占有8个字节,答案应该是8才对,为什么会有16出现呢?进入源码里面可以发现


alloc 分配内存图

证明例子2:

源码例子图:


Student 测试代码图

例子终端输出图:


例子输出图

这两个图得出两个结论:

第一:就是对于小于16的size,直接赋予16,否则就根据实际来分配内存,至于第二个例子为什么[Student class] 也是占用16个内存呢,是因为Student对象中还有两个成员变量,然后变量是int类型,int又占用4个字节,所以加起来应该就是8+4+4 = 16;

第二:就是structStudent_IMPL {

//    struct NSObject_IMPL NSObject_IVARS; //1

    Class isa; //2

    int_no;

    int_age;

};

1和2是对等的

下面的两张内存分布图可以说明这点,这里不做文字说明


对象内存分布图1
对象内存分布图2

另外查看两个成员变量的值,也可以通过xcode的内存来看:


xcode内存图

这个图也说明了,isa指针占用8个字节,_age,_no 各占4个

另外,还可以在这里通过lldb相关指令更改内存,例如现在我想将04 -->8

原始:

(lldb) x 0x0000000103402a80

0x103402a80: d1 11 00 00 01 80 1d 00 04 00 00 00 05 00 00 00  ................

0x103402a90: c1 c6 03 8f ff ff 1d 00 90 07 00 00 01 00 00 00  ................

 操作内存

对内存的操作,无非就是读写操作。 修改内存中的值:

memory write 内存地址 数值

如:memory write 0x103402a89 08

读取内存操作:

memory read/数量 _ 格式 _ 字节数 内存地址 或者 x/数量 _ 格式 _ 字节数 内存地址

更改查看:

(lldb) x 0x0000000103402a80

0x103402a80: 08 11 00 00 01 80 1d 00 08 00 00 00 05 00 00 00  ................

0x103402a90: c1 c6 03 8f ff ff 1d 00 90 07 00 00 01 00 00 00  ................


可以看到已经更改成功了

证明例子3:

源码图:


源码图
源码测试图


终端输出图:


终端输出图

结果分析图:


源码结构图
NSObject对象分布图
Person对象分布图
Student 内存分布图

从上面的图片展示,可以看到,对象的内存实际使用和分配内存都是遵循内存对齐的原则,也就是使用或者分配的内存大小必须是最大成员大小的倍数,例如Person对象分配16个对象,isa 占用8个指针,_age1 占用4个,按道理实际占用应该是12个,但是结果确显示了16个,说明使用的也是根据内存对齐的原则,可以从源码中出发探究的:

[Student alloc]-->[NSObject alloc]-->_objc_rootAlloc(Class cls)-->class_createInstance-->instanceSize-->alignedInstanceSize-->unalignedInstanceSize()--> return data()->ro->instanceSize-->word_align()

最后可以看到,对象的使用内存也是按照内存对齐法则来的


实际内存
内存对齐之后的实际内存


问题2:对象的isa指针指向哪里?


1.instance对象的isa指针指向class对象

2.class对象的isa指向meta-class对象

3.meta-class对象的isa指向基类的meta-class对象

一张图说明任何事:


isa指向图

证明例子:


对象的isa指向类对象
对象isa指针打印图
类对象isa指向元类图
类对象isa打印图
对象的superclass打印图


证明方法的寻找路径:

对象本身有方法图


对象本身没有方法找父类方法图

这个证明了当对象自身没有方法的时候会去查找父类中是否还有方法

类方法转对象方法图

在这里想补充一点的就是RootMetaClass 的superclass指针这个非常特殊,因为假如我调用的是一个类方法的时候,最后一直到RootMetaClass的superclass的时候,找的是对象方法;

问题3:OC的类信息存放在哪里?


1.对象方法、属性、成员变量、协议信息,存放在class对象中

每个类在内存中有且只有一个class对象

所以class一般会存放一些一次性的的内容,例如属性信息,对象方法,协议,成员变量等,进入objc的源码中可以看到的确如下:

struct objc_class :objc_object{

    // Class ISA;

    Class superclass;

    cache_t cache;            // formerly cache pointer and vtable

    class_data_bits_tbits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t*data() { 

        return bits.data();

    }

struct class_rw_t {

    // Be warned that Symbolication knows the layout of this structure.

    uint32_tflags;

    uint32_tversion;

    const class_ro_t *ro;

    method_array_t methods;

    property_array_t properties;

    protocol_array_t protocols;

    Class firstSubclass;

    Class nextSiblingClass;

    char *demangledName;

2.类方法,存放在meta-class对象中

3.成员变量的具体值,存放在instance对象,因为每个instance对象都拥有自己的变量

demo 测试图

从编译出来的C++源码和打印的对象地址值,可以证明上述观点3,因此object1,object2在内存中的体现形式应该就是如下:

instance 分布图

模拟源码测试分析结果:

实例对象存储属性和变量图


类方法存储图


元类对象存储图


常用指令:

将Objective-C代码转换成C/C++代码

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 输出的CPP文件

如果需要链接其他框架的话,需要使用-framework参数。比如-framework UIKit

LLDB 指令

print,p :打印

po:打印对象

读取内存:

memory read/数量格式字节数 内存地址

x/数量格式字节数 内存地址

数量:1,2,3........

格式:x16进制,f是浮点,d是10进制

字节数:b:byte 1 字节;h:half word 2字节;w:word 4字节;g:giant word 8字节

修改内存中的值

memory write 内存地址 数值

memory write 0x00000010 10


学习总结:

1.我们平时编写的Objective-C 代码,底层实现其实都是C、C++代码,然后再转换到汇编-->机器语言的


2.Objective-C的面向对象都是基于C、C++的数据结构实现的


3.Objective-C的对象或者类主要是基于C,C++的结构体数据结构实现的


4.class_getInstanceSize([NSObject class]) 代表创建一个实例对象至少需要多少内存,遵循内存对齐原则,malloc_size(__bridge const void *)obj)代表创建一个实例对象,实际上分配了多少内存?



参考链接:

apple源码

可以添加微信一起交流学习:fslskz

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容