Skip to content

Commit f5c6931

Browse files
committed
NSObject对象占用多少内存空间?
1 parent f24b751 commit f5c6931

File tree

2 files changed

+167
-18
lines changed

2 files changed

+167
-18
lines changed

Runtime/12.第十二题.md

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,78 @@
11
12.一个 `NSObject` 对象占用多少内存空间?
22

3-
受限于内存分配的机制,一个 `NSObject`对象都会分配 `16Bit` 的内存空间。
3+
> 结论:受限于内存分配的机制,一个 `NSObject`对象都会分配 `16Bit` 的内存空间。但是实际上在64位下,只使用了 `8bit`,在32位下,只使用了 `4bit`
44
5-
但是实际上在 64位 下,只使用了 `8bit`;
6-
在32位下,只使用了 `4bit`
75

8-
一个 NSObject 实例对象成员变量所占的大小,实际上是 8KB
9-
```objc
10-
#import <Objc/Runtime>
11-
Class_getInstanceSize([NSObject Class])
6+
首先`NSObject`对象的本质是一个`NSObject_IMPL`结构体。我们通过以下命令将 `Objecttive-C` 转化为 `C\C++`
7+
8+
```
9+
// 如果需要连接其他框架,可以使用 -framework 参数,例如 -framework UIKit
10+
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
11+
```
12+
13+
通过将`main.m`转化为`main.cpp` 文件可以看出它的结构包含一个`isa`指针:
14+
```c
15+
struct NSObject_IMPL {
16+
Class isa;
17+
};
18+
```
19+
20+
如果当前是继承自`NSObject``Person`类,结构如下:
21+
```c
22+
struct Person_IMPL {
23+
Class isa;
24+
// 自己的成员变量
25+
int _age;
26+
int _height;
27+
};
28+
```
29+
30+
or(参考上面 NSObject_IMPL 的结构)
31+
32+
```c
33+
struct Person_IMPL {
34+
struct NSObject_IMPL NSObject_IVARS;
35+
// 自己的成员变量
36+
int _age;
37+
int _height;
38+
};
1239
```
1340

14-
本质是
41+
下面通过一个例子来验证一下以上的结论
42+
43+
44+
45+
46+
47+
48+
初始化一个`NSObject`对象
1549
```objc
16-
size_t class_getInstanceSize(Class cls)
17-
{
18-
if (!cls) return 0;
19-
return cls->alignedInstanceSize();
20-
}
50+
NSObject *object = [[NSObject alloc] init];
2151
```
2252

23-
获取 Obj-C 指针所指向的内存的大小,实际上是16KB
53+
导入运行时头文件 `#import <objc/runtime.h>`,利用 `class_getInstanceSize` 方法,传入实例的类,即可获取当前实例实际占用内存的大小
54+
55+
2456
```objc
25-
#import <malloc/malloc.h>
26-
malloc_size((__bridge const void *)obj);
57+
NSLog(@"object 实际占用内存大小为 %zd",class_getInstanceSize([object class]));
58+
// 打印结果为 8
2759
```
2860

61+
之后我们导入 `#import <malloc/malloc.h>`
2962

30-
对象在分配内存空间时,会进行内存对齐,所以在 iOS 中,分配内存空间都是 16字节 的倍数。
3163

64+
```objc
65+
NSLog(@"object 指针指向内存的大小为 %zd",malloc_size((__bridge const void *)object));
66+
// 打印结果为 16
67+
```
3268

69+
`Class_getInstanceSize`底层实现:对象在分配内存空间时,会进行内存对齐,所以在 `iOS` 中,分配内存空间都是 `16字节` 的倍数。**如果存在继承关系,则需要父类的大小**
70+
```objc
71+
size_t class_getInstanceSize(Class cls)
72+
{
73+
if (!cls) return 0;
74+
return cls->alignedInstanceSize();
75+
}
76+
```
3377

34-
可以通过以下网址 :openSource.apple.com/tarballs 来查看源代码。
78+
可以通过以下网址 :[openSource.apple.com/tarballs](openSource.apple.com/tarballs) 来查看源代码。

Runtime消息转发.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# 1. Runtime消息转发
2+
3+
消息转发
4+
5+
如果当前类没有对应的实例方法,系统会调用如下方法,可以选择在这个时机动态添加
6+
7+
```objc
8+
+(BOOL)resolveInstanceMethod:(SEL)sel {
9+
10+
if (sel == @selector(eat)) {
11+
class_addMethod([self class], sel, (IMP)vc_eat, "v@:");
12+
return YES;
13+
}
14+
return [super resolveInstanceMethod:sel];
15+
}
16+
```
17+
18+
```objc
19+
void vc_eat(id obj,SEL _cmd) {
20+
NSLog(@"这是Eat方法");
21+
}
22+
```
23+
如果当前类没有对应的类方法,系统会调用如下方法,可以选择在这个时机动态添加
24+
25+
```objc
26+
+(BOOL) resolveClassMethod:(SEL)sel {
27+
if(sel == @selector(newPerson)) {
28+
// 找到当前类的 metaClass
29+
Class MetaClass = objc_getMetaClass([NSStringFromClass(self) UTF8String]);
30+
class_addMethod(MetaClass,sel,(IMP)vc_newPerson,"v@:");
31+
return YES;
32+
}
33+
return [super resolveClassMethod:sel];
34+
}
35+
```
36+
37+
```objc
38+
void vc_newPerson(id obj,SEL _cmd) {
39+
NSLog(@"当前是类方法 newPerson");
40+
}
41+
```
42+
43+
如果在当前类,以上两个方法都没有实现,可以将消息转发给其他的类处理
44+
45+
```objc
46+
- (id)forwardingTargetForSelector:(SEL)aSelector {
47+
if(aSelector == @selector(someMethod)) {
48+
return [SomeClass new];
49+
}
50+
return [super forwardingTargetForSelector:aSelector];
51+
}
52+
```
53+
54+
55+
Objecttive-C
56+
57+
58+
1. 我们日常编写的 Objecttive-C 需要经过一下流程转换为机器语言
59+
**Objecttive-C** -> **C\C++** -> **汇编语言** -> **机器语言**
60+
61+
62+
63+
64+
2.**Objecttive-C** 转化为 **C\C++**
65+
66+
```
67+
// 如果需要连接其他框架,可以使用 -framework 参数,例如 -framework UIKit
68+
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main.cpp
69+
```
70+
71+
**Objecttive-C** 对象是基于 C\C++ 的结构体实现的。
72+
73+
74+
3. NSObject 本质是一个 NSObject_IMPL 结构体
75+
76+
77+
```c
78+
struct NSObject_IMPL {
79+
Class isa;
80+
};
81+
82+
```
83+
84+
```objc
85+
NSObject *object = [[NSObject alloc] init];
86+
```
87+
88+
导入运行时头文件 `#import <objc/runtime.h>`,利用 `class_getInstanceSize` 方法,传入实例的类,即可获取当前实例占用内存的大小
89+
90+
91+
```objc
92+
NSLog(@"object 实际占用内存大小为 %zd",class_getInstanceSize([object class]));
93+
// 打印结果为 8
94+
```
95+
96+
之后我们导入 `#import <malloc/malloc.h>`
97+
98+
99+
```objc
100+
NSLog(@"object 指针指向内存的大小为 %zd",malloc_size((__bridge const void *)object));
101+
// 打印结果为 16
102+
```
103+
104+
内存对齐:
105+

0 commit comments

Comments
 (0)