lldb命令:
bt : 打印当前堆栈信息
register read xxx :读寄存器的信息
x objc2 <=>(等价) memory read objc2
x/4gx xxx x/8gx xxx
调试的3种方法:
1:添加符号断点直接跟流程。symbolic breakpoint
2:摁住control + step into,然后符号断点处查看源码
3:Xcode -> Debug -> Debug Workflow -> Always Show Disassembly,然后符号断点处查看源码
苹果开源源码:https://opensource.apple.com/
alloc流程:
// 第一步
+ (id)alloc {
return _objc_rootAlloc(self);
}
// 第二步
// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
// 第三步
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if (slowpath(checkNil && !cls)) return nil;
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No shortcuts available.
if (allocWithZone) {
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
// 第四步
NEVER_INLINE
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
{
// allocWithZone under __OBJC2__ ignores the zone parameter
return _class_createInstanceFromZone(cls, 0, nil,
OBJECT_CONSTRUCT_CALL_BADALLOC);
}
// 第五步
/***********************************************************************
* class_createInstance
* fixme
* Locking: none
*
* Note: this function has been carefully written so that the fastpath
* takes no branch.
**********************************************************************/
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);
}
}
设置编译器优化:
Xcode -> Build Settings -> Optimization Level
16字节对齐算法:
static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}
#define NANO_MAX_SIZE 256 /* Buckets sized {16, 32, 48, ..., 256} */
#define SHIFT_NANO_QUANTUM 4
#define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM) // 16
#define NANO_QUANTA_MASK (NANO_REGIME_QUANTA_SIZE - 1)
#define NANO_SIZE_CLASSES (NANO_MAX_SIZE/NANO_REGIME_QUANTA_SIZE)
static MALLOC_INLINE size_t
segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)
{
size_t k, slot_bytes;
if (0 == size) {
size = NANO_REGIME_QUANTA_SIZE; // Historical behavior
}
k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta
slot_bytes = k << SHIFT_NANO_QUANTUM; // multiply by power of two quanta size
*pKey = k - 1; // Zero-based!
return slot_bytes;
}
8字节对齐算法:
#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;
}
[LGPerson alloc] objc_alloc流程:
// 第一步
// Calls [cls alloc].
id
objc_alloc(Class cls)
{
return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}
// 第二步
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
#if __OBJC2__
if (slowpath(checkNil && !cls)) return nil;
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
return _objc_rootAllocWithZone(cls, nil);
}
#endif
// No shortcuts available.
if (allocWithZone) {
return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
}
return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
}
内存对齐原则:
1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储。 min(当前开始的位置m n) m=9 n=4 9 10 11 12
2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
3:收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍.不足的要补⻬。
struct LGStruct1 {
double a; // 8 (0-7)
char b; // 1 [8 1] (8)
int c; // 4 [9 4] 9 10 11 (12 13 14 15)
short d; // 2 [16 2] (16 17)
}struct1;
// 内部需要的大小为: 17
// 最大属性 : 8
// 结构体整数倍: 24
struct LGStruct2 {
double a; //8 (0-7)
int b; //4 (8 9 10 11)
char c; //1 (12)
short d; //2 13 (14 15) - 16
}struct2;
// 内部需要的大小为: 16
// 最大属性 : 8
// 结构体整数倍: 16
NSLog(@"%lu-%lu",sizeof(struct1),sizeof(struct2));
//输出结果为:24-16
内存开辟分析:
//sizeof
//class_getInstanceSize
//malloc_size
LGPerson *person = [LGPerson alloc];
person.name = @"Cooci";
person.nickName = @"KC";
NSLog(@"%lu - %lu - %lu",sizeof(person),class_getInstanceSize([LGPerson class]),malloc_size((__bridge const void *)(person)));
输出结果为:8 - 40 - 48
转换为16进制数:
//float -> 16进制
void lg_float2HEX(float f) {
union uuf {
float f; char s[4];
} uf;
uf.f = f;
printf("0x");
for (int i=3; i>=0; i--) {
printf("%02x",0xff & uf.s[i]);
}
printf("\n");
}
//double -> 16进制
void lg_double2HEX(double d) {
union uud {
double d; char s[4];
} ud;
ud.d = d;
printf("0x");
for (int i=7; i>=0; i--) {
printf("%02x",0xff & ud.s[i]);
}
printf("\n");
}
lg_float2HEX(12.0);
lg_double2HEX(14.0);
输出结果为:
0x41400000
0x402c000000000000
Clang是一个由Apple主导编写,基于LLVM的C/C++/Objective-C编译器
clang -rewrite-objc main.m -o main.cpp 把目标文件编译成c++文件
UIKit报错问题
clang -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 -isysroot / Applications/Xcode.app/Contents/Developer/Platforms/ iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.0.sdk main.m
xcode
安装的时候顺带安装了xcrun
命令,xcrun
命令在clang
的基础上进行了 一些封装,要更好用一些
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp (模拟器)
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main- arm64.cpp (手机)
objc_setProperty 与 objc_getProperty
void objc_setProperty(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, signed char shouldCopy)
{
bool copy = (shouldCopy && shouldCopy != MUTABLE_COPY);
bool mutableCopy = (shouldCopy == MUTABLE_COPY);
reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy);
}
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy)
{
if (offset == 0) {
object_setClass(self, newValue);
return;
}
id oldValue;
id *slot = (id*) ((char*)self + offset);
if (copy) {
newValue = [newValue copyWithZone:nil];
} else if (mutableCopy) {
newValue = [newValue mutableCopyWithZone:nil];
} else {
if (*slot == newValue) return;
newValue = objc_retain(newValue);
}
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
objc_release(oldValue);
}
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}
// Retain release world
id *slot = (id*) ((char*)self + offset);
if (!atomic) return *slot;
// Atomic retain release world
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
id value = objc_retain(*slot);
slotlock.unlock();
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}
结构体(struct)中所有变量是“共存”的——优点是“有容乃大”, 全面;
缺点是struct内存空间的分配是粗放的,不管用不用,全分配。
联合体(union)中是各变量是“互斥”的——缺点就是不够“包容”;
但优点是内存使用更为精细灵活,也节省了内存空间。
ISA:
# if __arm64__
# define ISA_MASK 0x0000000ffffffff8ULL
# define ISA_MAGIC_MASK 0x000003f000000001ULL
# define ISA_MAGIC_VALUE 0x000001a000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 19
# define RC_ONE (1ULL<<45)
# define RC_HALF (1ULL<<18)
# elif __x86_64__
# define ISA_MASK 0x00007ffffffffff8ULL
# define ISA_MAGIC_MASK 0x001f800000000001ULL
# define ISA_MAGIC_VALUE 0x001d800000000001ULL
# define ISA_BITFIELD \
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 8
# define RC_ONE (1ULL<<56)
# define RC_HALF (1ULL<<7)
# else
# error unknown architecture for packed isa
# endif
/*
nonpointer:表示是否对 isa 指针开启指针优化 0:纯isa指针,1:不止是类对象地址,isa 中包含了类信息、对象的引用计数等
has_assoc:关联对象标志位,0没有,1存在
has_cxx_dtor:该对象是否有 C++ 或者 Objc 的析构器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更快的释放对象
shiftcls:存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位用来存储类指针。
magic:用于调试器判断当前对象是真的对象还是没有初始化的空间
weakly_referenced:志对象是否被指向或者曾经指向一个 ARC 的弱变量,没有弱引用的对象可以更快释放。
deallocating:标志对象是否正在释放内存
has_sidetable_rc:当对象引用技术大于 10 时,则需要借用该变量存储进位
extra_rc:当表示该对象的引用计数值,实际上是引用计数值减 1, 例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10, 则需要使用到下面的 has_sidetable_rc。
*/
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
Class cls;
uintptr_t bits;
#if defined(ISA_BITFIELD)
struct {
ISA_BITFIELD; // defined in isa.h
};
#endif
};
dealloc流程图:
// 第一步
// Replaced by NSZombies
- (void)dealloc {
_objc_rootDealloc(self);
}
// 第二步
void
_objc_rootDealloc(id obj)
{
ASSERT(obj);
obj->rootDealloc();
}
// 第三步
inline void
objc_object::rootDealloc()
{
if (isTaggedPointer()) return; // fixme necessary?
if (fastpath(isa.nonpointer &&
!isa.weakly_referenced &&
!isa.has_assoc &&
!isa.has_cxx_dtor &&
!isa.has_sidetable_rc))
{
assert(!sidetable_present());
free(this);
}
else {
object_dispose((id)this);
}
}
// 第四步
id
object_dispose(id obj)
{
if (!obj) return nil;
objc_destructInstance(obj);
free(obj);
return nil;
}
// 第五步
/***********************************************************************
* objc_destructInstance
* Destroys an instance without freeing memory.
* Calls C++ destructors.
* Calls ARC ivar cleanup.
* Removes associative references.
* Returns `obj`. Does nothing if `obj` is nil.
**********************************************************************/
void *objc_destructInstance(id obj)
{
if (obj) {
// Read all of the flags at once for performance.
bool cxx = obj->hasCxxDtor();
bool assoc = obj->hasAssociatedObjects();
// This order is important.
if (cxx) object_cxxDestruct(obj);
if (assoc) _object_remove_assocations(obj);
obj->clearDeallocating();
}
return obj;
}