从内存管理方面:主要比较对于强引用和弱引用的实现逻辑进行比较
1,从引用计数讨论:oc的相对复杂,但是swift的管理性能更加优越.典型的用空间换时间.
oc为isa指针引用计数管理,和SidetablesMap对象全局管理引用计数.在少于19位时采用isa指针存储,过高时采用Sidetable存储
# 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
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table;
}
对于swift呢?,在每个对象都有一个refCounts的引用计数,由于单独给引用计数分配了一个成员变量,它的存储空间远大于isa指针存储,这个时候就不需要要sidetable这个全局map,避免了查看和多线程读写的加锁等待
struct HeapObject {
/// This is always a valid pointer to a metadata object.
HeapMetadata const *metadata;
// Initialize a HeapObject header as appropriate for a newly-allocated object.
constexpr HeapObject(HeapMetadata const *newMetadata)
: metadata(newMetadata)
, refCounts(InlineRefCounts::Initialized)
{ }
};
2,从弱引用对象讨论:oc采用Sidetable存储弱引用的指针,在dealloc的时候进行设置为nil的操作,从外层api来看,swift在对象deinit的时候读取的引用指针也是nil,但是实现逻辑完全不同,他引入了弱引用对象的概念,把对象分为deinit和dealloc两个生命周期,在对象引用计数为0的时候,如果弱引用计数不为0,改内存不会释放,当外接有访问改弱引用对象是会把改值设为nil,并把弱引用计数减一,当弱引用计数也为0时改内存才会释放.从设计方式看也是用空间来换取时间的思路,避免了oc的map查找,所以从这也可以看出对于现在手机电脑内存没有那么紧张的今天,通过空间来换取时间的方案是非常不错的想法.
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table;
}
class HeapObjectSideTableEntry {
// FIXME: does object need to be atomic?
std::atomic<HeapObject*> object;
SideTableRefCounts refCounts;
public:
HeapObjectSideTableEntry(HeapObject *newObject)
: object(newObject), refCounts()
{ }
};
class SideTableRefCountBits : public RefCountBitsT<RefCountNotInline>
{
uint32_t weakBits;
// ...
};