Objective-C 对象的本质 01 - 底层实现
Objective-C 对象的本质 01 - 底层实现
我们平时编写的 Objective-C 代码,底层实现为 C/C++ 代码。
Objective-C --> C/C++ --> 汇编 --> 机器码。
Objective-C 的面向对象是基于 C/C++ 的==结构体==实现的。
在终端里使用 ==xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc class.m -o class.cpp== 命令可以将 Objective-C 转换为 C++ 代码。
Objective-C 底层实现:
// Objective-C
@interface NSObject {
Class isa;
}
@end
// C++: NSObject Implementation
// 存储了 Class 对象的 isa 和 其他成员变量
struct NSObject_IMPL {
Class isa; // 8 Byte
};
// Class 指针
typedef struct objc_class *Class;
// id,可以作为任何对象的指针
typedef struct objc_object *id;
// Tips:子类的的结构体实现中有一个成员为父类的结构体
struct Bar_IMPL {
struct Foo_IMPL Foo_IVARS;
// ivars...
}
一个 Objective-C(假设没有属性) 对象占用多少内存?
- 先抛结论:一个没有属性的 Objective-C 对象占用 16 Byte 的内存空间。
- 使用 class_getInstanceSize() 函数可以查看一个类底层结构体占用的内存大小(结构体需要内存对齐),返回 8 Byte。
- 使用 malloc_size() 函数可以查看一个对象占用的内存大小,16 Byte。
试验:在类中不断添加 int 属性(4 Byte),再次调用 class_getInstanceSize() 和 malloc_size()。
- 添加 1 ~ 2 个 int 属性:
- class_getInstanceSize():return 16 Byte,
- malloc_size():return 16 Byte,
- 添加 3 ~ 4 个 int 属性:
- class_getInstanceSize():return 24 Byte,
- malloc_size():return 32 Byte,
- 添加 5 ~ 6 个 int 属性:
- class_getInstanceSize():return 32 Byte,
- malloc_size():return 32 Byte,
- 添加 7 ~ 8 个 int 属性:
- class_getInstanceSize():return 40 Byte,
- malloc_size():return 48 Byte,
结论:
- class_getInstanceSize():在添加 int 属性的过程中,NSObject_IMPL 结构体中宽度最大的元素始终为 isa 指针变量,所以结构体的大小为 8 Byte 的整倍数 。
- malloc_size():实际在为对象分配内存空间时,大小为 16 Byte 的整倍数。
补充:通过在控制台使用 memory read 指令打印对象的内存数据,也可以看到长度为 16 Byte。
访问内存的 LLDB 命令:
通过上面的试验可以知道,实际上在实例化一个对象时,需要分配至少 16 Byte 的内存空间,接下来看看相关的源码。
在 objc4-723 版本的源码中,从 objc/Project-Headers/objc-runtime-new.h 文件中的 objc_class 结构体中,有一个 instanceSize() 函数(1279 ~ 1284 行),返回值 >= 16,1281 行的注释为:“// CF requires all objects be at least 16 bytes.”,通过跟踪类的 alloc 方法内部的调用链,可以看到在分配内存前调用了 instanceSize() 函数,calloc() 函数根据这个函数的返回值分配内存空间给对象使用,并且会保证内存大小为 16 Byte 的整倍数。
class_getInstanceSize() 函数在苹果开源的 objc4 源码中可以看到。
// objc/Source/objc-class.mm // // 查看一个类底层结构体占用的内存大小(结构体需要内存对齐) size_t class_getInstanceSize(Class cls) { if (!cls) return 0; return cls->alignedInstanceSize(); // 调用 objc_class 结构体中的函数 }
核心源码
objc_object、objc_class
// objc/Project-Headers/objc-private.h
//
// objc_class 的基类,主要存储了 Meta-Class 对象的 isa
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
// initIsa() should be used to init the isa of new objects only.
// If this object already has an isa, use changeIsa() for correctness.
// initInstanceIsa(): objects with no custom RR/AWZ
// initClassIsa(): class objects
// initProtocolIsa(): protocol objects
// initIsa(): other objects
void initIsa(Class cls /*nonpointer=false*/);
void initClassIsa(Class cls /*nonpointer=maybe*/);
void initProtocolIsa(Class cls /*nonpointer=maybe*/);
void initInstanceIsa(Class cls, bool hasCxxDtor);
// changeIsa() should be used to change the isa of existing objects.
// If this is a new object, use initIsa() for performance.
Class changeIsa(Class newCls);
};
// objc/Project-Headers/objc-runtime-new.h
//
// Class、Meta-Class 都是通过 objc_class 实现的
//
// 作为 Class 使用时,存储了:
// isa:Meta-Class 对象的 isa
// superclass:父类的 Class 对象,如果没有父类,superclass 为 nil
// bits.data().ro.ivars:成员变量信息(ivar_list_t)
// bits.data().properties:属性信息(method_array_t)
// bits.data().methods:成员方法信息 (property_array_t)
// bits.data().protocols:协议信息(protocol_array_t)
//
// 作为 Meta-Class 使用时,存储了:
// isa:基类的 Meta-Class 对象的 isa,基类的 Meta-Class 对象的 isa 指向自身
// superclass:父类的 Meta-Class 对象,
// 基类的 Meta-Class 对象的 superclass 指向基类的 Class 对象
// bits.data().methods:类方法的信息
//
struct objc_class : objc_object {
// Class ISA; // isa,继承自 objc_object
Class superclass; // 父类的 Class 对象或 Meta-Class 对象
cache_t cache; // 方法缓存
class_data_bits_t bits; // 存放 Class 或 Meta-Class 信息对象的指针
class_rw_t *data() {
return bits.data();
}
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
// Locking: To prevent concurrent realization, hold runtimeLock.
bool isRealized() {
return data()->flags & RW_REALIZED;
}
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
}
};
RW_REALIZED、word_align()
// objc/Project-Headers/objc-runtime-new.h
//
// Values for class_rw_t->flags
// These are not emitted by the compiler and are never used in class_ro_t.
// Their presence should be considered in future ABI versions.
// class_t->data is class_rw_t, not class_ro_t
#define RW_REALIZED (1<<31)
// objc/Project-Headers/objc-os.h
//
#ifdef __LP64__
# define WORD_SHIFT 3UL
# define WORD_MASK 7UL
# define WORD_BITS 64
#else
# define WORD_SHIFT 2UL
# define WORD_MASK 3UL
# define WORD_BITS 32
#endif
static inline uint32_t word_align(uint32_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
static inline size_t word_align(size_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
class_data_bits_t、class_rw_t、class_ro_t
// objc/Project-Headers/objc-runtime-new.h
// data pointer
#define FAST_DATA_MASK 0x00007ffffffffff8UL
// objc/Project-Headers/objc-runtime-new.h
//
// 存放类信息对象的指针
struct class_data_bits_t {
// Values are the FAST_ flags above.
uintptr_t bits; // typedef unsigned long uintptr_t;
class_rw_t* data() {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
};
// objc/Project-Headers/objc-runtime-new.h
//
// 存放类的成员(变量、属性、方法)信息、协议信息或类方法信息,包含分类中的属性、方法、协议信息
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint32_t version;
const class_ro_t *ro;
method_array_t methods; // 成员方法信息或类方法信息(包含分类的方法信息)
property_array_t properties; // 属性信息(包含分类的属性信息)
protocol_array_t protocols; // 协议信息(包含分类的协议信息)
Class firstSubclass;
Class nextSiblingClass;
char *demangledName;
#if SUPPORT_INDEXED_ISA
uint32_t index;
#endif
};
// objc/Project-Headers/objc-runtime-new.h
//
// 存放类的成员(变量、属性、方法)信息、协议信息或类方法信息,不包含分类中的属性、方法、协议信息
struct class_ro_t {
uint32_t flags;
uint32_t instanceStart;
uint32_t instanceSize; // 类底层结构体占用的内存大小
#ifdef __LP64__
uint32_t reserved;
#endif
const uint8_t * ivarLayout;
const char * name; // 类名
method_list_t * baseMethodList; // 成员方法信息或类方法信息(不包含分类的方法信息)
protocol_list_t * baseProtocols;// 协议信息(不包含分类的协议信息)
const ivar_list_t * ivars; // 成员变量信息
const uint8_t * weakIvarLayout;
property_list_t *baseProperties;// 属性信息(不包含分类的属性信息)
method_list_t *baseMethods() const {
return baseMethodList;
}
};
SEL、IMP
// 方法名(选择器)
//
// 可以通过 @selector() 或 sel_registerName() 获取 SEL。
// 可以通过 sel_getName() 或 NSStringFromSelector() 将 SEL 转换为字符串。
// 不同类中的同名方法所对应的 SEL 是相同的。
//
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;
// 函数指针
//
/// A pointer to the function of a method implementation.
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ );
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...);
#endif
bucket_t、cache_t
typedef unsigned long uintptr_t;
// 方法缓存中的 Key
#if __LP64__
typedef uint32_t mask_t; // x86_64 & arm64 asm are less efficient with 16-bits
#else
typedef uint16_t mask_t;
#endif
typedef uintptr_t cache_key_t;
// 方法缓存
struct bucket_t {
private:
cache_key_t _key; // key 是方法的 SEL
IMP _imp; // 函数指针
public:
inline cache_key_t key() const { return _key; }
inline IMP imp() const { return (IMP)_imp; }
inline void setKey(cache_key_t newKey) { _key = newKey; }
inline void setImp(IMP newImp) { _imp = newImp; }
void set(cache_key_t newKey, IMP newImp);
};
// 方法缓存列表
//
// 用散列表(哈希表)来缓存调用多的方法,可以提高查找方法的速度。
//
// _mask 为什么是 _buckets 的长度 -1 ?
// -1 能确保 (key & _mask) <= (_buckets 的长度 - 1),用来作为 _buckets 的下标来取值。
// 在 cache_t::find() 函数中可以看到计算下标的代码。
//
// _buckets 的动态扩容:
// 向 _buckets 添加最后一个缓存时会进行扩容。
// 每次扩容为原来的两倍(2^n)。
// 扩容时会将缓存清除,因为扩容后 _mask 发生了变化。
// 通过 cache_t::expand() 函数中进行扩容。
struct cache_t {
struct bucket_t *_buckets; // 散列表
mask_t _mask; // 散列表的长度 -1
mask_t _occupied; // 已经缓存的方法数量(<= _mask)
public:
struct bucket_t *buckets();
mask_t mask();
mask_t occupied();
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void initializeToEmpty();
mask_t capacity();
bool isConstantEmptyCache();
bool canBeFreed();
static size_t bytesForCapacity(uint32_t cap);
static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
void expand();
void reallocate(mask_t oldCapacity, mask_t newCapacity);
struct bucket_t * find(cache_key_t key, id receiver);
static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
};
其它源码
entsize_list_tt、list_array_tt
// 数组,ivar_list_t、method_list_t、property_list_t 都是 entsize_list_tt 的子类型。
/***********************************************************************
* entsize_list_tt<Element, List, FlagMask>
* Generic implementation of an array of non-fragile structs.
*
* Element is the struct type (e.g. method_t)
* List is the specialization of entsize_list_tt (e.g. method_list_t)
* FlagMask is used to stash extra bits in the entsize field
* (e.g. method list fixup markers)
**********************************************************************/
template <typename Element, typename List, uint32_t FlagMask>
struct entsize_list_tt {
uint32_t entsizeAndFlags;
uint32_t count;
Element first;
uint32_t entsize() const;
uint32_t flags() const;
Element& getOrEnd(uint32_t i) const;
Element& get(uint32_t i) const;
size_t byteSize() const;
List* duplicate() const;
struct iterator;
const iterator begin() const;
const iterator end() const;
struct iterator {
uint32_t entsize;
uint32_t index; // keeping track of this saves a divide in operator-
Element* element;
iterator() { }
iterator(const List& list, uint32_t start = 0)
: entsize(list.entsize())
, index(start)
, element(&list.getOrEnd(start))
{ }
};
};
// 数组,property_array_t、method_array_t、protocol_array_t 都是 list_array_tt 的子类型。
/***********************************************************************
* list_array_tt<Element, List>
* Generic implementation for metadata that can be augmented by categories.
*
* Element is the underlying metadata type (e.g. method_t)
* List is the metadata's list type (e.g. method_list_t)
*
* A list_array_tt has one of three values:
* - empty
* - a pointer to a single list
* - an array of pointers to lists
*
* countLists/beginLists/endLists iterate the metadata lists
* count/begin/end iterate the underlying metadata elements
**********************************************************************/
template <typename Element, typename List>
class list_array_tt {
struct array_t {
uint32_t count;
List* lists[0];
static size_t byteSize(uint32_t count) {
return sizeof(array_t) + count * sizeof(lists[0]);
}
size_t byteSize() {
return byteSize(count);
}
};
protected:
class iterator {
List **lists;
List **listsEnd;
typename List::iterator m, mEnd;
};
public:
uint32_t count();
iterator begin();
iterator end();
uint32_t countLists();
List** beginLists();
List** endLists();
template<typename Result>
Result duplicate();
};
ivar_t、ivar_list_t
// 成员变量信息
struct ivar_t {
int32_t *offset;
const char *name; // 变量名
const char *type; // 数据类型
uint32_t alignment_raw;
uint32_t size; // 占用内存大小
uint32_t alignment() const {
if (alignment_raw == ~(uint32_t)0) return 1U << WORD_SHIFT;
return 1 << alignment_raw;
}
};
struct ivar_list_t : entsize_list_tt<ivar_t, ivar_list_t, 0> {
bool containsIvar(Ivar ivar) const {
return (ivar >= (Ivar)&*begin() && ivar < (Ivar)&*end());
}
};
method_t、method_list_t、method_array_t
// 方法信息
//
// *types 示意:| 返回值 | 参数1 | 参数2 | ... | 参数n |
// 例如一个没有返回值且没有参数的方法,它的 method_t 中的 *types 为 v16@:8
// | v16 | @0 | :8 |
// | void | id | SEL |
// 两个参数为默认参数,id 对应 self,SEL 对应 _cmd
//
// *types 中的数字:
// 第一个数字:所有参数一共占用多少字节
// 后面的数字:当前参数从第几个字节开始
struct method_t {
SEL name; // 方法名
const char *types; // 包含了返回值类型、参数类型的编码字符串
IMP imp; // 函数指针
};
// 方法信息列表(一维数组)
// Two bits of entsize are used for fixup markers.
struct method_list_t : entsize_list_tt<method_t, method_list_t, 0x3> {
bool isFixedUp() const;
void setFixedUp();
uint32_t indexOfMethod(const method_t *meth) const {
uint32_t i = (uint32_t)(((uintptr_t)meth - (uintptr_t)this) / entsize());
assert(i < count);
return i;
}
};
// 方法信息列表(二维数组)
class method_array_t : public list_array_tt<method_t, method_list_t> {
typedef list_array_tt<method_t, method_list_t> Super;
public:
method_list_t **beginCategoryMethodLists() {
return beginLists();
}
method_list_t **endCategoryMethodLists(Class cls);
method_array_t duplicate() {
return Super::duplicate<method_array_t>();
}
};
Type Encoding(通过 @encode() 可以查看指定类型的字符串编码)
property_t、property_list_t、property_array_t
struct property_t {
const char *name;
const char *attributes;
};
struct property_list_t : entsize_list_tt<property_t, property_list_t, 0> {
};
class property_array_t : public list_array_tt<property_t, property_list_t> {
typedef list_array_tt<property_t, property_list_t> Super;
public:
property_array_t duplicate() {
return Super::duplicate<property_array_t>();
}
};
protocol_t、protocol_list_t、protocol_array_t
typedef uintptr_t protocol_ref_t; // protocol_t *, but unremapped
// Values for protocol_t->flags
#define PROTOCOL_FIXED_UP_2 (1<<31) // must never be set by compiler
#define PROTOCOL_FIXED_UP_1 (1<<30) // must never be set by compiler
// Bits 0..15 are reserved for Swift's use.
#define PROTOCOL_FIXED_UP_MASK (PROTOCOL_FIXED_UP_1 | PROTOCOL_FIXED_UP_2)
struct protocol_t : objc_object {
const char *mangledName;
struct protocol_list_t *protocols;
method_list_t *instanceMethods;
method_list_t *classMethods;
method_list_t *optionalInstanceMethods;
method_list_t *optionalClassMethods;
property_list_t *instanceProperties;
uint32_t size; // sizeof(protocol_t)
uint32_t flags;
// Fields below this point are not always present on disk.
const char **_extendedMethodTypes;
const char *_demangledName;
property_list_t *_classProperties;
const char *demangledName();
const char *nameForLogging() {
return demangledName();
}
bool isFixedUp() const;
void setFixedUp();
# define HAS_FIELD(f) (size >= offsetof(protocol_t, f) + sizeof(f))
bool hasExtendedMethodTypesField() const {
return HAS_FIELD(_extendedMethodTypes);
}
bool hasDemangledNameField() const {
return HAS_FIELD(_demangledName);
}
bool hasClassPropertiesField() const {
return HAS_FIELD(_classProperties);
}
# undef HAS_FIELD
const char **extendedMethodTypes() const {
return hasExtendedMethodTypesField() ? _extendedMethodTypes : nil;
}
property_list_t *classProperties() const {
return hasClassPropertiesField() ? _classProperties : nil;
}
};
struct protocol_list_t {
// count is 64-bit by accident.
uintptr_t count;
protocol_ref_t list[0]; // variable-size
size_t byteSize() const {
return sizeof(*this) + count*sizeof(list[0]);
}
protocol_list_t *duplicate() const {
return (protocol_list_t *)memdup(this, this->byteSize());
}
typedef protocol_ref_t* iterator;
typedef const protocol_ref_t* const_iterator;
const_iterator begin() const {
return list;
}
iterator begin() {
return list;
}
const_iterator end() const {
return list + count;
}
iterator end() {
return list + count;
}
};
class protocol_array_t : public list_array_tt<protocol_ref_t, protocol_list_t> {
typedef list_array_tt<protocol_ref_t, protocol_list_t> Super;
public:
protocol_array_t duplicate() {
return Super::duplicate<protocol_array_t>();
}
};