Files
knowledge-kit/Chapter1 - iOS/1.87.md
2020-08-10 20:16:18 +08:00

158 lines
5.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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个字节。
![image-20200726130625217](/Users/lbp/Library/Application Support/typora-user-images/image-20200726130625217.png)
![image-20200726125926892](/Users/lbp/Library/Application Support/typora-user-images/image-20200726125926892.png)
发现 `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` 返回的就是指针指向的对象大小.
![image-20200726130920234](/Users/lbp/Library/Application Support/typora-user-images/image-20200726130920234.png)
结论:
- 当某个类继承自 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 个字节大小的空间用来存放 ivars64位系统
2. 某个类继承自 NSObject 的情况,内存如何分配