mac 12.2.1
xcode 13.2.1
objc4-838
1.alloc的流程
alloc ->
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
// Calls [cls alloc].
id
objc_alloc(Class cls)
{
return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}
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));
}
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);
}
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 (!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);
}
2.类结构原理
x/4gx p/x po
x/6gx LGPerson.class
8
cache_t cache; =16
p/x
//属性 VS 成员变量
@interface LGPerson : NSObject{
NSString *subject;
}
@property(nonatomic,copy) NSString *name;
@property(nonatomic,copy) NSString *hobby;
-(void)satNB;
+(void)sayNB666;
@end
struct cache_t {
private:
explicit_atomic
union {
struct {
explicit_atomic
#if __LP64__
uint16_t _flags; //2
#endif
uint16_t _occupied;//2
};
explicit_atomic
};
union isa_t {
isa_t() { }
isa_t(uintptr_t value) : bits(value) { }
uintptr_t bits;
private:
// Accessing the class requires custom ptrauth operations, so
// force clients to go through setClass/getClass by making this
// private.
Class cls;
struct objc_object {
private:
isa_t isa;
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() const {
return bits.data();
}
#define FAST_DATA_MASK 0x00007ffffffffff8UL
class_rw_t* data() const {
return (class_rw_t *)(bits & FAST_DATA_MASK);
}
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint16_t witness;
#if SUPPORT_INDEXED_ISA
uint16_t index;
#endif
explicit_atomic
Class firstSubclass;
Class nextSiblingClass;
(lldb) x/4gx LGPerson.class
0x100008278: 0x00000001000082a0 0x0000000100801140
0x100008288: 0x0000000100ad4880 0x0002802c00000003
(lldb) p/x 0x100008278+0x20
(long) $1 = 0x0000000100008298
(lldb) p (class_data_bits_t *)0x0000000100008298
(class_data_bits_t *) $2 = 0x0000000100008298
(lldb) p $2->data()
(class_rw_t *) $3 = 0x0000000100ad4610
(lldb) p *$3
(class_rw_t) $4 = {
flags = 2148007936
witness = 1
ro_or_rw_ext = {
std::__1::atomic
Value = 4295000136
}
}
firstSubclass = nil
nextSiblingClass = 0x00007ff8428edac8
}
(lldb) p $3.properties()
(const property_array_t) $5 = {
list_array_tt
= {
list = {
ptr = 0x00000001000081a8
}
arrayAndFlag = 4295000488
}
}
}
Fix-it applied, fixed expression was:
$3->properties()
(lldb) p $5.list
(const RawPtr
ptr = 0x00000001000081a8
}
(lldb) p $6.ptr
(property_list_t *const) $7 = 0x00000001000081a8
(lldb) p *$7
(property_list_t) $8 = {
entsize_list_tt
}
(lldb) p $8.get(0)
(property_t) $9 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")
(lldb)
(lldb) p $8.get(1)
(property_t) $12 = (name = "hobby", attributes = "T@\"NSString\",C,N,V_hobby")
(lldb)
(lldb) p $3->methods()
(const method_array_t) $10 = {
list_array_tt
= {
list = {
ptr = 0x0000000100008090
}
arrayAndFlag = 4295000208
}
}
}
(lldb) p $10.list.ptr
(method_list_t *const) $11 = 0x0000000100008090
(lldb) p $10.list
(const method_list_t_authed_ptr
ptr = 0x0000000100008090
}
(lldb) p $13.ptr
(method_list_t *const) $14 = 0x0000000100008090
(lldb) p *$14
(method_list_t) $15 = {
entsize_list_tt
}
(lldb) p $15.get(0)
(method_t) $16 = {}
(lldb) p $15.get(0).big()
(method_t::big) $17 = {
name = "satNB"
types = 0x0000000100003f92 "v16@0:8"
imp = 0x0000000100003ca0 (KCObjcBuild`-[LGPerson satNB])
}
(lldb) p $15.get(1).big()
(method_t::big) $18 = {
name = "hobby"
types = 0x0000000100003f8a "@16@0:8"
imp = 0x0000000100003d30 (KCObjcBuild`-[LGPerson hobby])
}
(lldb) p $15.get(2).big()
(method_t::big) $19 = {
name = "setHobby:"
types = 0x0000000100003f9a "v24@0:8@16"
imp = 0x0000000100003d60 (KCObjcBuild`-[LGPerson setHobby:])
}
(lldb) p $15.get(3).big()
(method_t::big) $20 = {
name = "init"
types = 0x0000000100003f8a "@16@0:8"
imp = 0x0000000100003c10 (KCObjcBuild`-[LGPerson init])
}
(lldb) p $15.get(4).big()
(method_t::big) $21 = {
name = "name"
types = 0x0000000100003f8a "@16@0:8"
imp = 0x0000000100003cd0 (KCObjcBuild`-[LGPerson name])
}
(lldb) p $15.get(5).big()
(method_t::big) $22 = {
name = ".cxx_destruct"
types = 0x0000000100003f92 "v16@0:8"
imp = 0x0000000100003d90 (KCObjcBuild`-[LGPerson .cxx_destruct])
}
(lldb) p $15.get(6).big()
(method_t::big) $23 = {
name = "setName:"
types = 0x0000000100003f9a "v24@0:8@16"
imp = 0x0000000100003d00 (KCObjcBuild`-[LGPerson setName:])
}
(lldb) p LGPerson.class
(Class) $1 = 0x0000000100008410
(lldb) p/x 0x0000000100008410+0x20
(long) $2 = 0x0000000100008430
(lldb) p (class_data_bits_t *)0x0000000100008430
(class_data_bits_t *) $3 = 0x0000000100008430
(lldb) p $3->data()
(class_rw_t *) $4 = 0x0000000100e59cb0
(lldb) p *$4
(class_rw_t) $5 = {
flags = 2148007936
witness = 1
ro_or_rw_ext = {
std::__1::atomic
Value = 4295000448
}
}
firstSubclass = 0x00000001000083e8
nextSiblingClass = 0x00007ff85597aac8
}
(lldb) p $5.ro()
(const class_ro_t *) $6 = 0x0000000100008180
(lldb) p * $6
(const class_ro_t) $7 = {
flags = 388
instanceStart = 8
instanceSize = 32
reserved = 0
= {
ivarLayout = 0x0000000100003eb4 "\U00000003"
nonMetaclass = 0x0000000100003eb4
}
name = {
std::__1::atomic
Value = 0x0000000100003eb6 "LGPerson"
}
}
baseMethods = {
ptr = 0x00000001000081c8
}
baseProtocols = nil
ivars = 0x0000000100008278
weakIvarLayout = 0x0000000000000000
baseProperties = 0x00000001000082e0
_swiftMetadataInitializer_NEVER_USE = {}
}
(lldb) p $7.ivars
(const ivar_list_t *const) $8 = 0x0000000100008278
(lldb) p *$8
(const ivar_list_t) $9 = {
entsize_list_tt
}
(lldb) p $9.get(0)
(ivar_t) $10 = {
offset = 0x00000001000083a8
name = 0x0000000100003f31 "subject"
type = 0x0000000100003f78 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $9.get(1)
(ivar_t) $11 = {
offset = 0x00000001000083b0
name = 0x0000000100003f39 "_name"
type = 0x0000000100003f78 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $9.get(2)
(ivar_t) $12 = {
offset = 0x00000001000083b8
name = 0x0000000100003f3f "_hobby"
type = 0x0000000100003f78 "@\"NSString\""
alignment_raw = 3
size = 8
}
(lldb) p $9.get(3)
(lldb) p $9.get(0).big()
(lldb) x/4gx LGPerson.class
0x1000082e8: 0x0000000100008310 0x0000000100801140
0x1000082f8: 0x0000000100f7c4d0 0x0002803400000003
(lldb) p/x 0x0000000100008310 & 0x00007ffffffffff8UL
(unsigned long) $1 = 0x0000000100008310
(lldb) po 0x0000000100008310
LGPerson
(lldb) p/x (class_data_bits_t *) 0x0000000100008330
(class_data_bits_t *) $3 = 0x0000000100008330
(lldb) p $3->data()
(class_rw_t *) $4 = 0x0000000100a232c0
(lldb) p *$4
(class_rw_t) $5 = {
flags = 2684878849
witness = 1
ro_or_rw_ext = {
std::__1::atomic
Value = 4311216753
}
}
firstSubclass = nil
nextSiblingClass = 0x00007ff8468abef0
}
(lldb) p $5.methods()
(const method_array_t) $6 = {
list_array_tt
= {
list = {
ptr = 0x0000000100008280
}
arrayAndFlag = 4295000704
}
}
}
(lldb) p $6.list
(const method_list_t_authed_ptr
ptr = 0x0000000100008280
}
(lldb) p $7.ptr
(method_list_t *const) $8 = 0x0000000100008280
(lldb) p *$8
(method_list_t) $9 = {
entsize_list_tt
}
(lldb) p $9.get(0).big()
(method_t::big) $10 = {
name = "sayNB666"
types = 0x0000000100003f47 "v16@0:8"
imp = 0x0000000100003d00 (KCObjcBuild`+[LGPerson sayNB666] at main.m:46)
}
(lldb)
(lldb) p LGPerson.class
(Class) $1 = 0x0000000100008410
(lldb) p/x 0x0000000100008410+0x20
(long) $2 = 0x0000000100008430
(lldb) p (class_data_bits_t *)0x0000000100008430
(class_data_bits_t *) $3 = 0x0000000100008430
(lldb) p $3->data()
(class_rw_t *) $4 = 0x0000000100a232c0
(lldb) p *$4
(class_rw_t) $5 = {
flags = 2684878849
witness = 1
ro_or_rw_ext = {
std::__1::atomic
Value = 4311216753
}
}
firstSubclass = nil
nextSiblingClass = 0x00007ff8468abef0
}
(lldb) p $5.protocols()
(const protocol_array_t) $6{
}
(lldb) p $6.list
(const RawPtr
}
(lldb) p $7.ptr
(Protocol_list_t *const) $8
(lldb) p *$8
(Protocol_list_t)$9
(lldb) p $9.list[0]
(protocol_ref_t) $10
(lldb) p (protocol_t *)$10
(protocol_t *)$11
(lldb) p *$11
{{(struct objc_selector *)"init", "@16@0:8", (void *)_I_LGPerson_init},
{(struct objc_selector *)"satNB", "v16@0:8", (void *)_I_LGPerson_satNB},
@16@0:8
/*
1: @ id
2: 16 :占用内存
3: @ :id
4: 0: 从0 位置开始
5: : SEL
6: 8 从8 位置开始
*/
@property(nonatomic,copy) NSString *nickName;
@property(nonatomic,strong) NSString *name;
@property(atomic,strong) NSString *hobby;
static void _I_LGPerson_setNickName_(LGPerson * self, SEL _cmd, NSString *nickName) { objc_setProperty (self, _cmd, __OFFSETOFIVAR__(struct LGPerson, _nickName), (id)nickName, 0, 1); }
static void _I_LGPerson_setName_(LGPerson * self, SEL _cmd, NSString *name) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_name)) = name; }
static void _I_LGPerson_setHobby_(LGPerson * self, SEL _cmd, NSString *hobby) { (*(NSString **)((char *)self + OBJC_IVAR_$_LGPerson$_hobby)) = hobby; }
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);
}
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);
}
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);
}
- (Class)class {
return object_getClass(self);
}
+ (Class)superclass {
return self->getSuperclass();
}
- (Class)superclass {
return [self class]->getSuperclass();
}
+ (BOOL)isMemberOfClass:(Class)cls {
return self->ISA() == cls;
}
- (BOOL)isMemberOfClass:(Class)cls {
return [self class] == cls;
}
+ (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = self->ISA(); tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
- (BOOL)isKindOfClass:(Class)cls {
for (Class tcls = [self class]; tcls; tcls = tcls->getSuperclass()) {
if (tcls == cls) return YES;
}
return NO;
}
// Calls [obj class]
Class
objc_opt_class(id obj)
{
#if __OBJC2__
if (slowpath(!obj)) return nil;
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
return cls->isMetaClass() ? obj : cls;
}
#endif
return ((Class(*)(id, SEL))objc_msgSend)(obj, @selector(class));
}
// Calls [obj isKindOfClass]
BOOL
objc_opt_isKindOfClass(id obj, Class otherClass)
{
#if __OBJC2__
if (slowpath(!obj)) return NO;
Class cls = obj->getIsa();
if (fastpath(!cls->hasCustomCore())) {
for (Class tcls = cls; tcls; tcls = tcls->getSuperclass()) {
if (tcls == otherClass) return YES;
}
return NO;
}
#endif
return ((BOOL(*)(id, SEL, Class))objc_msgSend)(obj, @selector(isKindOfClass:), otherClass);
}
objc_opt_isKindOfClass
BOOL re1 = [(id)[NSObject class] isKindOfClass:[NSObject class]]; //1
BOOL re2 = [(id)[NSObject class] isMemberOfClass:[NSObject class]]; //0
BOOL re3 = [(id)[LGPerson class] isKindOfClass:[LGPerson class]]; //0
BOOL re4 = [(id)[LGPerson class] isMemberOfClass:[LGPerson class]]; //0
NSLog(@" re1 :%hhd\n re2 :%hhd\n re3 :%hhd\n re4 :%hhd\n",re1,re2,re3,re4);
BOOL re5 = [(id)[NSObject alloc] isKindOfClass:[NSObject class]]; //1
BOOL re6 = [(id)[NSObject alloc] isMemberOfClass:[NSObject class]]; //1
BOOL re7 = [(id)[LGPerson alloc] isKindOfClass:[LGPerson class]]; //1
BOOL re8 = [(id)[LGPerson alloc] isMemberOfClass:[LGPerson class]]; //1
NSLog(@" re5 :%hhd\n re6 :%hhd\n re7 :%hhd\n re8 :%hhd\n",re5,re6,re7,re8);
struct cache_t {
private:
explicit_atomic
union {
struct {
explicit_atomic
#if __LP64__
uint16_t _flags;
#endif
uint16_t _occupied;
};
explicit_atomic
};
(lldb) p/x pClass
(Class) $0 = 0x0000000100008318
(lldb) p (cache_t *)0x0000000100008318
(cache_t *) $1 = 0x0000000100008318
(lldb) p *$1
(cache_t) $2 = {
_bucketsAndMaybeMask = {
std::__1::atomic
Value = 4295000896
}
}
= {
= {
_maybeMask = {
std::__1::atomic
Value = 8393024
}
}
_flags = 1
_occupied = 0
}
_originalPreoptCache = {
std::__1::atomic
Value = 0x0000000100801140
}
}
}
}
(lldb) p $2._bucketsAndMaybeMask
(explicit_atomic
std::__1::atomic
Value = 4295000896
}
}
(lldb) p $2._maybeMask
(explicit_atomic
std::__1::atomic
Value = 8393024
}
}
(lldb) p $2._originalPreoptCache
(explicit_atomic
std::__1::atomic
Value = 0x0000000100801140
}
}
(lldb) p $5.value()
error:
$5.value()
~~ ^
(lldb) p $2.buckets()
(bucket_t *) $6 = 0x0000000100008340
(lldb) p *$6
(bucket_t) $7 = {
_sel = {
std::__1::atomic
Value = "\xf0\U00000010\x80"
}
}
_imp = {
std::__1::atomic
Value = 4303360240
}
}
}
(lldb) p [per satNB]
2022-03-23 17:22:40.314152+0800 KCObjcBuild[7258:92946] satNB
(lldb) p/x pClass
(Class) $8 = 0x0000000100008318
(lldb) p (cache_t *)0x0000000100008318
(cache_t *) $9 = 0x0000000100008318
(lldb) p *$9
(cache_t) $10 = {
_bucketsAndMaybeMask = {
std::__1::atomic
Value = 4295000896
}
}
= {
= {
_maybeMask = {
std::__1::atomic
Value = 8393024
}
}
_flags = 1
_occupied = 0
}
_originalPreoptCache = {
std::__1::atomic
Value = 0x0000000100801140
}
}
}
}
(lldb) p $10.buckets()
(bucket_t *) $11 = 0x0000000100008340
(lldb) p *$11
(bucket_t) $12 = {
_sel = {
std::__1::atomic
Value = "\xf0\U00000010\x80"
}
}
_imp = {
std::__1::atomic
Value = 4303360240
}
}
}
(lldb) p $10.buckets()[1]
(bucket_t) $13 = {
_sel = {
std::__1::atomic
Value = (null)
}
}
_imp = {
std::__1::atomic
Value = 246518237888512
}
}
}
(lldb) p $12.sel()
(SEL) $14 = "\xf0\U00000010\x80"
(lldb) p $13.sel()
(SEL) $15 = ""
(lldb) p $13.imp()
error:
$13.imp()
~~~~~~~ ^
note: 'imp' declared here
(lldb) p $12.imp()
error:
$12.imp()
~~~~~~~ ^
note: 'imp' declared here
(lldb) p $12.imp(nil,pClass)
(IMP) $16 = 0x00000000008093e8 (0x00000000008093e8)
(lldb) p $13.imp(nil,pClass)
(IMP) $17 = 0x0000e03400008318 (0x0000e03400008318)
(lldb) p *$14
(SEL) $18 = "\xf0\U00000010\x80"
(lldb)
typedef uint32_t mask_t;
struct kc_bucket_t {
SEL _sel;
IMP _imp;
};
struct kc_cache_t {
struct kc_bucket_t *_bukets;
// uintptr_t _bucketsAndMaybeMask;
mask_t _maybeMask;
uint16_t _flags;
uint16_t _occupied;
};
struct kc_class_data_bits_t {
uintptr_t bits;
};
struct kc_objc_class{
Class isa;
// Class ISA;
Class superclass;
struct kc_cache_t cache; // formerly cache pointer and vtable
struct kc_class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
};
LGPerson *per = [[LGPerson alloc]init];
Class pClass = per.class;
[per satNB];
//
struct kc_objc_class *kc_class =(__bridge struct kc_objc_class *) (pClass);
NSLog(@"%hu--%u",kc_class->cache._occupied,kc_class->cache._maybeMask);
//1--7
for (mask_t i = 0; i< kc_class->cache._maybeMask;i++ ) {
struct kc_bucket_t buckets = kc_class->cache._bukets[i];
NSLog(@"%@--%p",NSStringFromSelector(buckets._sel),buckets._imp);
}
/*
2022-03-23 18:01:38.736487+0800 KCObjcBuild[7745:122662] 1--7
2022-03-23 18:01:38.736558+0800 KCObjcBuild[7745:122662] (null)--0x0
2022-03-23 18:01:38.736599+0800 KCObjcBuild[7745:122662] (null)--0x0
2022-03-23 18:01:38.736865+0800 KCObjcBuild[7745:122662] satNB--0xb4d0
2022-03-23 18:01:38.736913+0800 KCObjcBuild[7745:122662] (null)--0x0
2022-03-23 18:01:38.736950+0800 KCObjcBuild[7745:122662] (null)--0x0
2022-03-23 18:01:38.736985+0800 KCObjcBuild[7745:122662] (null)--0x0
2022-03-23 18:01:38.737019+0800 KCObjcBuild[7745:122662] (null)--0x0
*/
void cache_t::insert(SEL sel, IMP imp, id receiver)
{
printf("======== %s- %p --%p \n",(char*)sel,imp,receiver);
mask_t newOccupied = occupied() + 1;
unsigned oldCapacity = capacity(), capacity = oldCapacity;
if (sel == @selector(say1)) {
bucket_t *kc_b = buckets();
for (unsigned i =0; i< oldCapacity; i++) {
SEL kc_sel = kc_b[i].sel();
IMP kc_imp = kc_b[i].imp(kc_b, nil);
printf("%p- %p - %p \n",kc_sel,kc_imp,&kc_b[i]);
}
printf("is-------%p- %u - %u --%u \n",kc_b,capacity,newOccupied,oldCapacity);
}
(lldb) p [per say1]
======== respondsToSelector:- 0x1007e87b0 --0x100a3ba50
======== class- 0x1007e8470 --0x100a3ba50
======== say1- 0x100003730 --0x100a3ba50
2022-03-29 17:38:46.191989+0800 KCObjcBuild[7271:188335] -[LGPerson say1]
======== retain- 0x1007e9140 --0x100e1cca0
======== release- 0x1007e92c0 --0x100e1cca0
======== dealloc- 0x1007e9400 --0x100e1cca0
(lldb) p [per say1]
======== respondsToSelector:- 0x1007e8770 --0x100a0e130
======== class- 0x1007e8430 --0x100a0e130
======== say1- 0x100003730 --0x100a0e130
0x0- 0x0 - 0x100e36b70
0x0- 0x0 - 0x100e36b80
0x0- 0x0 - 0x100e36b90
0x0- 0x0 - 0x100e36ba0
0x0- 0x0 - 0x100e36bb0
0x7ff81f2be2e5- 0x7e0020 - 0x100e36bc0
0x0- 0x0 - 0x100e36bd0
0x1- 0x100e36b70 - 0x100e36be0
is-------0x100e36b70- 8 - 2 --8
2022-03-29 17:45:56.407530+0800 KCObjcBuild[7319:191889] -[LGPerson say1]
======== retain- 0x1007e9100 --0x100e37220
======== release- 0x1007e9280 --0x100e37220
======== dealloc- 0x1007e93c0 --0x100e37220