起因:
Matrix中OC对象的类型获取不到,详见https://github.com/Tencent/matrix/issues/514
原因:nsobject_hook_alloc_method是hook了NSObject alloc方法进行记录类名信息,但是一些case下OC对象创建并不会走alloc
+ (id)event_logging_alloc {
id object = [self event_logging_alloc];
if (is_thread_ignoring_logging()) {
return object;
}
nsobject_set_last_allocation_event_name(object, class_getName(self.class));
return object;
}
打符号断点测试如下:
NSObject *obj0 = [[NSObject alloc] init]; //不走alloc和allocWithZone,走_objc_rootAllocWithZone
NSObject *obj0_1 = [NSObject new]; //同上
NSObject *obj1 = [[UIView alloc] init]; //走_objc_rootAllocWithZone,走CALayer allocWithZone+_objc_rootAllocWithZone,走NSObject alloc+allocWithZone
NSObject *obj1_1 = [UIView new]; //同上
NSObject *obj2 = @"sfjksafsdsfdsf"; //不走alloc、allocWithZone、_objc_rootAllocWithZone
NSObject *obj2_1 = [NSString stringWithString:@"sfjksafsdsfdsf"]; //不走alloc、_objc_rootAllocWithZone,走allocWithZone
NSObject *obj2_2 = [NSString new]; //不走alloc、_objc_rootAllocWithZone,走allocWithZone
NSObject *obj3 = [NSData data]; //不走alloc、_objc_rootAllocWithZone,走NSData、_NSZeroData allocWithZone
NSObject *obj3_1 = [NSData new]; //同上
NSObject *obj4 = [NSArray array]; //走alloc,走allocWithZone,不走_objc_rootAllocWithZone
NSObject *obj4_1 = @[]; //不走alloc、allocWithZone、_objc_rootAllocWithZone
NSObject *obj5 = [NSDictionary dictionary]; //走alloc,走allocWithZone,不走_objc_rootAllocWithZone
NSObject *obj5_1 = @{}; //不走alloc、allocWithZone、_objc_rootAllocWithZone
不走alloc的case:
1.顶级类NSObject:走_objc_rootAllocWithZone
2.字面量(@"sfjksafsdsfdsf"、@[]、@{}):直接objc_retain
3. NSString/NSData类方法:走allocWithZone(NSArray/NSDictionary走alloc和allocWithZone)
探究 [NSData data]
//不走alloc、_objc_rootAllocWithZone,走NSData、_NSZeroData allocWithZone
Foundation`+[NSData(NSData) data]:
0x18b310894 <+0>: stp x29, x30, [sp, #-0x10]!
0x18b310898 <+4>: mov x29, sp
0x18b31089c <+8>: adrp x8, 228993
0x18b3108a0 <+12>: add x1, x8, #0xc03 ; =0xc03
0x18b3108a4 <+16>: mov x2, #0x0
0x18b3108a8 <+20>: bl 0x18ad3a080 ; objc_msgSend
-> 0x18b3108ac <+24>: adrp x8, 228993
0x18b3108b0 <+28>: add x1, x8, #0x874 ; =0x874
0x18b3108b4 <+32>: mov x2, #0x0
0x18b3108b8 <+36>: mov x3, #0x0
0x18b3108bc <+40>: bl 0x18ad3a080 ; objc_msgSend
0x18b3108c0 <+44>: ldp x29, x30, [sp], #0x10
0x18b3108c4 <+48>: b 0x18ad58080 ; objc_autorelease
// allocWithZone -> NSAllocateObject -> class_createInstance -> calloc -> malloc_zone_calloc
给0x18ad3a080下断点,po $x0、x/s $x1可知 [NSData data]方法内部直接调用了[NSData allocWithZone:]方法
// objc4源码调试调用栈为
* frame #0: 0x00000001986c3894 Foundation`+[NSData(NSData) allocWithZone:]
frame #1: 0x000000010035a738 libobjc.A.dylib`objc_allocWithZone [inlined] callAlloc(cls=0x00000002026d9450, checkNil=true, allocWithZone=true) at NSObject.mm:1935:16
frame #2: 0x000000010035a6c0 libobjc.A.dylib`objc_allocWithZone(cls=0x00000002026d9450) at NSObject.mm:1960:12
frame #3: 0x000000019872f4d4 Foundation`__19+[_NSZeroData data]_block_invoke + 24
frame #4: 0x0000000100471dcc libdispatch.dylib`_dispatch_client_callout + 20
frame #5: 0x0000000100473d34 libdispatch.dylib`_dispatch_once_callout + 156
frame #6: 0x000000019872f4b8 Foundation`+[_NSZeroData data] + 64
frame #7: 0x00000001986c3978 Foundation`-[_NSPlaceholderData initWithBytes:length:copy:deallocator:] + 124
frame #8: 0x000000019872f460 Foundation`+[NSData(NSData) data] + 36
总结:
没有自定义的allocWithZone方法就走_class_createInstanceFromZone(nil)逻辑,调用instanceSize、calloc、initInstanceIsa等逻辑。
有自定义allocWithZone方法就走自定义allocWithZone方法。
注:iOS断点调试和objc4参考源码因内敛函数编译优化和平台差异会有一定不同,大体逻辑一致。
// 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));
}
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);
}
网友评论