總結
- 結構體內存對齊: 結構體內存的大小必須是最大成員內存大小的倍數
- 操作系統有分配內存對齊的概念(Bucket Size), 大都以16個字節爲單位對齊
- 在iOS堆空間中分配內存的話都是16的倍數,也就是說iOS堆內存中最小內存的大小爲16, 這樣對於操作系統訪問CPU是最優最快的。(如果結構體的成員變量只需要24個字節就夠用,而iOS中分配堆內存大小是32個字節)
- class_getInstanceSize( )返回某個類對象至少需要多少空間
- malloc_size()返回的是實例對象實際分配的內存空間
一、面向對象
1.1 Objective-C的本質
-
我們平時編寫的Objective-C代碼,底層實現其實都是C\C++代碼
-
所以Objective-C的面向對象都是基於C\C++的數據結構實現的
-
思考:Objective-C的對象、類主要是基於C\C++的什麼數據結構實現的?
- 結構體
-
將Objective-C代碼轉換爲C\C++代碼
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc OC源文件 -o 輸出的CPP文件
- 如果需要鏈接其他框架,使用-framework參數。比如-framework UIKit
1.2 OC對象的本質
- 思考:一個OC對象在內存中是如何佈局的?
- NSObject的底層實現
- 一個普通類的底層實現
- 思考:一個Person對象、一個Student對象佔用多少內存空間?
1.3 實時查看內存數據
- Debug -> Debug Workfllow -> View Memory (Shift + Command + M)
- 也可以使用LLDB指令
1.4 2個容易混淆的函數
- 創建一個實例對象,至少需要多少內存?
#import <objc/runtime.h>
class_getInstanceSize([NSObject class]);
- 創建一個實例對象,實際上分配了多少內存?
#import <malloc/malloc.h>
malloc_size((__bridge const void *)obj);
二、常用LLDB指令
-
print、p : 打印
-
po : 打印對象
-
讀取內存
memory read/數量格式字節數 內存地址
x/數量格式字節數 內存地址
x/3xw 0x10010
- 修改內存中的值
memory write 內存地址 數值
memory write 0x0000010 10
-
格式
- x是16進制,f是浮點,d是10進制
-
字節大小
- b : byte 1字節,
- h : half word 2字節
- w : word 4字節,
- g : giant word 8字節
三、OC對象的分類
- Objective-C中的對象,簡稱OC對象,主要可以分爲3種
- instance對象(實例對象)
- class對象(類對象)
- meta-class對象(元類對象)
3.1 instance
- instance對象就是通過類alloc出來的對象,每次調用alloc都會產生新的instance對象
NSObject *object1 = [[NSObject alloc] init];
NSObject *object2 = [[NSObject alloc] init];
-
object1、object2是NSObject的instance對象(實例對象)
-
它們是不同的兩個對象,分別佔據着兩塊不同的內存
-
instance對象在內存中存儲的信息包括
- isa指針
- 其他成員變量
-
Person對象
@interface MJPerson : NSObject {
@public
int _age;
}
@end
- Person對象使用
MJPerson *p1 = [[MJPerson alloc] init];
p1->_age = 3;
MJPerson *p2 = [[MJPerson alloc] init];
p2->_age = 4;
3.2 class
- objectClass1 ~ objectClass5都是NSObject的class對象(類對象)
- 它們是同一個對象。每個類在內存中有且只有一個class對象
ClassobjectClass1 = [object1 class];
Class objectClass2 = [object2 class];
Class objectClass3 = object_getClass(object1); // Runtime API
Class objectClass4 = object_getClass(object2); // Runtime API
Class objectClass5 = [NSObject class];
- class對象在內存中存儲的信息主要包括
- isa指針
- superclass指針
- 類的屬性信息(@property)、類的對象方法信息(instance method)
- 類的協議信息(protocol)、類的成員變量信息(ivar)
- …
3.3 meta-class
Class objectMetaClass = object_getClass(objectClass5);
-
objectMetaClass是NSObject的
meta-class
對象(元類對象) -
每個類在內存中有且只有一個meta-class對象
-
meta-class對象和class對象的內存結構是一樣的,但是用途不一樣,在內存中存儲的信息主要包括
isa
指針superclass
指針- 類的
類方法
信息(class method) - …
3.4 注意
- 以下代碼獲取的objectClass是class對象,並不是meta-class對象
Class objectMetaClass2 = [[[NSObject class] class] class];
3.5 查看Class是否爲meta-class
#import <objc/runtime.h>
BOOL result = class_isMetaClass([NSObject class]);
四、isa 和 superclass
4.1 isa指針
-
instance的isa指向class
- 當調用對象方法時,通過instance的isa找到class,最後找到對象方法的實現進行調用
-
class的isa指向meta-class
- 當調用類方法時,通過class的isa找到meta-class,最後找到類方法的實現進行調用
4.2 class對象的superclass指針
- 當Student的instance對象要調用Person的對象方法時
- 會先通過isa找到Student的class
- 然後通過superclass找到Person 的class
- 最後找到對象方法的實現進行調用
4.3 isa、superclass總結
-
instance的isa指向class
-
class的isa指向meta-class
-
meta-class的isa指向基類的meta-class
-
class的superclass指向父類的class p 如果沒有父類,superclass指針爲nil
-
meta-class的superclass指向父類的meta-class p 基類的meta-class的superclass指向基類的class
-
instance調用對象方法的軌跡
- isa找到class,方法不存在,就通過superclass找父類
-
class調用類方法的軌跡
- isa找meta-class,方法不存在,就通過superclass找父類
五、Class的結構
5.1 isa指針
- 從64bit開始,isa需要進行一次位運算,才能計算出真實地址
5.2 objc4源碼下載
5.3 窺探struct objc_class的結構
- class、meta-class對象的本質結構都是struct objc_class
5.4 objc_getClass和object_getClass的區別
-
Class objc_getClass(const char *aClassName)
1> 傳入字符串類名
2> 返回對應的類對象 -
Class object_getClass(id obj)
1> 傳入的obj可能是instance對象、class對象、meta-class對象
2> 返回值- a) 如果是instance對象,返回class對象
- b) 如果是class對象,返回meta-class對象
- c) 如果是meta-class對象,返回NSObject(基類)的meta-class對象
-
- (Class)class、+ (Class)class
1> 返回的就是類對象
- (Class) {
return self->isa;
}
+ (Class) {
return self;
}