mirror of
https://github.com/NohamR/knowledge-kit.git
synced 2026-05-25 12:27:15 +00:00
158 lines
5.1 KiB
Markdown
158 lines
5.1 KiB
Markdown
# Objective-C 底层
|
||
|
||
1. Objective-C 中对象、类主要是基于 C/C++ 中的结构体实现的。
|
||
|
||
方法一:
|
||
|
||
可以用 clang 验证。`clang -rewrite-objc main.m -o main.cpp`
|
||
转到指定平台代码。`xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp`
|
||
|
||
```
|
||
struct NSObject_IMPL {
|
||
Class isa;
|
||
};
|
||
|
||
/// An opaque type that represents an Objective-C class.
|
||
typedef struct objc_class *Class;
|
||
```
|
||
|
||
所以 Class 是指向结构体的指针,所以在 64 位系统中占据8个字节,32位系统占据4个字节。
|
||
|
||
NSObject 就是结构体占据8个字节。
|
||
|
||

|
||
|
||

|
||
|
||
发现 `class_getInstanceSize` 和 `malloc_size` 结果不一致。
|
||
|
||
```c
|
||
// Class's ivar size rounded up to a pointer-size boundary.
|
||
uint32_t alignedInstanceSize() const {
|
||
return word_align(unalignedInstanceSize());
|
||
}
|
||
```
|
||
|
||
`class_getInstanceSize` 返回的是类的实例对象的成员变量的大小(四舍五入等于指针指向对象的大小,所以不精确)
|
||
|
||
```c
|
||
extern size_t malloc_size(const void *ptr);
|
||
/* Returns size of given ptr */
|
||
```
|
||
|
||
`malloc_size` 返回的就是指针指向的对象大小.
|
||
|
||

|
||
|
||
结论:
|
||
|
||
- 当某个类继承自 NSObject 的时候,如果没有其他属性,则这个类占据16个字节。`class_getInstanceSize` 占据 8 , `malloc_size` 占据 16
|
||
- 当某个类继承自 NSObject 的时候,如果有其他属性,则这个类占据16个字节。`class_getInstanceSize` 占据 16 , `malloc_size` 占据 16
|
||
|
||
方法二: 从源代码角度出发验证(从上大下)
|
||
|
||
```c++
|
||
// NSObject.mm
|
||
// Replaced by ObjectAlloc
|
||
+ (id)allocWithZone:(struct _NSZone *)zone {
|
||
return _objc_rootAllocWithZone(self, (malloc_zone_t *)zone);
|
||
}
|
||
|
||
// objc-class-old.mm
|
||
id
|
||
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone)
|
||
{
|
||
id obj;
|
||
|
||
if (fastpath(!zone)) {
|
||
obj = class_createInstance(cls, 0);
|
||
} else {
|
||
obj = class_createInstanceFromZone(cls, 0, zone);
|
||
}
|
||
|
||
if (slowpath(!obj)) obj = _objc_callBadAllocHandler(cls);
|
||
return obj;
|
||
}
|
||
|
||
// objc-class-old.mm
|
||
/***********************************************************************
|
||
* _class_createInstance. Allocate an instance of the specified
|
||
* class with the specified number of bytes for indexed variables, in
|
||
* the default zone, using _class_createInstanceFromZone.
|
||
**********************************************************************/
|
||
static id _class_createInstance(Class cls, size_t extraBytes)
|
||
{
|
||
return _class_createInstanceFromZone (cls, extraBytes, nil);
|
||
}
|
||
|
||
|
||
|
||
static ALWAYS_INLINE id
|
||
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
|
||
int construct_flags = OBJECT_CONSTRUCT_NONE,
|
||
bool cxxConstruct = true,
|
||
size_t *outAllocatedSize = nil)
|
||
{
|
||
ASSERT(cls->isRealized());
|
||
|
||
// Read class's info bits all at once for performance
|
||
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
|
||
bool hasCxxDtor = cls->hasCxxDtor();
|
||
bool fast = cls->canAllocNonpointer();
|
||
size_t size;
|
||
|
||
size = cls->instanceSize(extraBytes);
|
||
if (outAllocatedSize) *outAllocatedSize = size;
|
||
|
||
id obj;
|
||
if (zone) {
|
||
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
|
||
} else {
|
||
obj = (id)calloc(1, size);
|
||
}
|
||
if (slowpath(!obj)) {
|
||
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
|
||
return _objc_callBadAllocHandler(cls);
|
||
}
|
||
return nil;
|
||
}
|
||
|
||
if (!zone && fast) {
|
||
obj->initInstanceIsa(cls, hasCxxDtor);
|
||
} else {
|
||
// Use raw pointer isa on the assumption that they might be
|
||
// doing something weird with the zone or RR.
|
||
obj->initIsa(cls);
|
||
}
|
||
|
||
if (fastpath(!hasCxxCtor)) {
|
||
return obj;
|
||
}
|
||
|
||
construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
|
||
return object_cxxConstructFromClass(obj, cls, construct_flags);
|
||
}
|
||
|
||
// objc-runtime-new.h
|
||
// Class's ivar size rounded up to a pointer-size boundary.
|
||
uint32_t alignedInstanceSize() const {
|
||
return word_align(unalignedInstanceSize());
|
||
}
|
||
|
||
// objc-runtime-new.h
|
||
size_t instanceSize(size_t extraBytes) const {
|
||
if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
|
||
return cache.fastInstanceSize(extraBytes);
|
||
}
|
||
|
||
size_t size = alignedInstanceSize() + extraBytes;
|
||
// CF requires all objects be at least 16 bytes.
|
||
if (size < 16) size = 16;
|
||
return size;
|
||
}
|
||
```
|
||
|
||
`CF requires all objects be at least 16 bytes.` 系统为 NSObject 对象分配了至少16个字节大小的空间,但是它使用了 8 个字节大小的空间用来存放 ivars(64位系统)
|
||
|
||
2. 某个类继承自 NSObject 的情况,内存如何分配
|