autorelease pool 释放的时候 最后调用 page->releaseUntil(&stop) stop 数值为nil 然后一个个释放 object_release(object) 只是 引用计数 -1? 从sideTable reconf 借了1位 借完清空 refcnts 并没有dealloc
真正dealloc的时候 调用 deinstance methond destorycxx 里面包含 IVAR 去除关联对象 destroysidetable weak表 跟 refcnts
popPage(void *token, AutoreleasePoolPage *page, id *stop) {
page->releaseUntil(stop) {
id obj = *--page->next;
objc_release(obj);
objc_object::rootRelease()
{
return rootRelease(true, RRVariant::Fast);
}
objc_object::rootRelease(bool performDealloc, objc_object::RRVariant variant) {
return sidetable_release(sideTableLocked, performDealloc) {
else if (! (refcnt & SIDE_TABLE_RC_PINNED)) {
refcnt -= SIDE_TABLE_RC_ONE;
}
} -> sidetable 表里 refcnt - 1
uintptr_t carry;
newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry); // extra_rc--
// Try to remove some retain counts from the side table.
auto borrow = sidetable_subExtraRC_nolock(RC_HALF);
bool emptySideTable = borrow.remaining == 0; // we'll clear the side table if no refcounts remain there
if (borrow.borrowed > 0) {
// Side table retain count decreased.
// Try to add them to the inline count.
bool didTransitionToDeallocating = false;
newisa.extra_rc = borrow.borrowed - 1; // redo the original decrement too
把side table 表里的count放到 isa extra_rc
减为0 后 清空 side table refcnts
newisa.has_sidetable_rc = !emptySideTable;
// Decrement successful after borrowing from side table.
if (emptySideTable)
sidetable_clearExtraRC_nolock() {
table.refcnts.erase(it);
}
* 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, /*deallocating*/true);
obj->clearDeallocating();
}
return obj;
}
return一个变量的时候, 正常是放到 autoreleasepool里, objc_autorelease(obj)
但是有2个优化调用,
callee:
objc_autoreleaseReturnValue (+ 1) objc_retainAutoreleaseReturnValue (+ 0)
就是把value 放到 TLS里面,
caller:
caller去TLS查找, 然后也调用上面2个方法?
// Prepare a value at +1 for return through a +0 autoreleasing convention.
id
objc_autoreleaseReturnValue(id obj)
{
if (prepareOptimizedReturn(ReturnAtPlus1)) return obj;
-> optimized method put obj in tls
return objc_autorelease(obj); -> normal autorelease
}
// Prepare a value at +0 for return through a +0 autoreleasing convention.
id
objc_retainAutoreleaseReturnValue(id obj)
{
if (prepareOptimizedReturn(ReturnAtPlus0)) return obj;
-> optimized method put in tls
// not objc_autoreleaseReturnValue(objc_retain(obj))
// because we don't need another optimization attempt
return objc_retainAutoreleaseAndReturn(obj);
-> normal retain and release
}
objc_retainAutorelease(id obj)
{
return objc_autorelease(objc_retain(obj));
}
Fast handling of return through Cocoa's +0 autoreleasing convention.
The caller and callee cooperate to keep the returned object
out of the autorelease pool and eliminate redundant retain/release pairs.
An optimized callee looks at the caller's instructions following the
return. If the caller's instructions are also optimized then the callee
skips all retain count operations: no autorelease, no retain/autorelease.
Instead it saves the result's current retain count (+0 or +1) in
thread-local storage. If the caller does not look optimized then
the callee performs autorelease or retain/autorelease as usual.
An optimized caller looks at the thread-local storage. If the result
is set then it performs any retain or release needed to change the
result from the retain count left by the callee to the retain count
desired by the caller. Otherwise the caller assumes the result is
currently at +0 from an unoptimized callee and performs any retain
needed for that case.
There are two optimized callees:
objc_autoreleaseReturnValue
result is currently +1. The unoptimized path autoreleases it.
objc_retainAutoreleaseReturnValue
result is currently +0. The unoptimized path retains and autoreleases it.
There are two optimized callers:
objc_retainAutoreleasedReturnValue
caller wants the value at +1. The unoptimized path retains it.
objc_unsafeClaimAutoreleasedReturnValue
caller wants the value at +0 unsafely. The unoptimized path does nothing.
Example:
Callee:
// compute ret at +1
return objc_autoreleaseReturnValue(ret);
Caller:
ret = callee();
ret = objc_retainAutoreleasedReturnValue(ret);
// use ret at +1 here
Callee sees the optimized caller, sets TLS, and leaves the result at +1.
Caller sees the TLS, clears it, and accepts the result at +1 as-is.
`