Write in front: iOS underlying principle exploration is my usual development and learning in the accumulation of a section of advanced road. Record my continuous exploration of the journey, I hope to be helpful to all readers.Copy the code
The directory is as follows:
- IOS underlying principles of alloc exploration
- The underlying principles of iOS are explored
- The underlying principles of iOS explore the nature of objects & isa’s underlying implementation
- Isa-basic Principles of iOS (Part 1)
- Isa-basic Principles of iOS (Middle)
- Isa-class Basic Principles of iOS Exploration (2)
- IOS fundamentals explore the nature of Runtime Runtime & methods
- Objc_msgSend: Exploring the underlying principles of iOS
- Slow lookups in iOS Runtime
- A dynamic approach to iOS fundamentals
- The underlying principles of iOS explore the message forwarding process
- Dyld (part 1)
- IOS Basic Principles of application loading principle dyld (ii)
- IOS basic principles explore the loading of classes
- The underlying principles of iOS explore the loading of categories
- IOS underlying principles to explore the associated object
- IOS underlying principle of the wizard KVC exploration
- Exploring the underlying principles of iOS: KVO Principles | More challenges in August
- Exploring the underlying principles of iOS: Rewritten KVO | More challenges in August
- The underlying principles of iOS: Multi-threading | More challenges in August
- GCD functions and queues in iOS
- GCD principles of iOS (Part 1)
- IOS Low-level – What do you know about deadlocks?
- IOS Low-level – Singleton destruction is possible?
- IOS Low-level – Dispatch Source
- IOS bottom – a fence letter blocks the number
- IOS low-level – Be there or be Square semaphore
- IOS underlying GCD – In and out into a scheduling group
- Basic principles of iOS – Basic use of locks
- IOS underlying – @synchronized Flow analysis
- IOS low-level – The principle of lock exploration
- IOS Low-level – allows you to implement a read/write lock
- Implementation of Objective-C Block
- Implementation of Objective-C Block
- IOS bottom – Block, comprehensive resolution!
- IOS Basics – Startup Optimization (part 1)
- IOS Basics – Startup Optimization (2)
- Exploration of basic principles of iOS — Memory management of memory five areas
- Tagged Pointer Format Changes for memory management
Summary of the above column
- Summary of iOS underlying principles of exploration
Sort out the details
- Summary of iOS development details
preface
Following on from the previous article, we moved on to the OC Memory management series on the flow of weak reference tables.
Sidetable_retain begins today’s source code reading
id
objc_object: :sidetable_retain(bool locked){#ifSUPPORT_NONPOINTER_ISA ASSERT(! isa.nonpointer); #endif SideTable& table = SideTables()[this];
if(! locked) table.lock(); size_t& refcntStorage = table.refcnts[this];
if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
refcntStorage += SIDE_TABLE_RC_ONE;
}
table.unlock();
return (id)this;
}
Copy the code
SideTable
struct SideTable {
spinlock_t slock;
// Reference count table
RefcountMap refcnts;
// weak reference table (__weak)
weak_table_t weak_table;
SideTable() {
memset(&weak_table, 0, sizeof(weak_table));
}
~SideTable() {
_objc_fatal("Do not delete SideTable.");
}
void lock() { slock.lock(); }
void unlock() { slock.unlock(); }
void forceReset() { slock.forceReset(); }
// Address-ordered lock discipline for a pair of side tables.
template<HaveOld, HaveNew>
static void lockTwo(SideTable *lock1, SideTable *lock2);
template<HaveOld, HaveNew>
static void unlockTwo(SideTable *lock1, SideTable *lock2);
};
Copy the code
The system maintains multiple sideTables (if there is only one table, all the objects will be very expensive to use (query, lock)), and the multiple tables will store the objects separately, with the use of the freed objects can be optimized for table storage. The routine operation of space for time.
A weak reference table
Start with a test print that doesn’t look very scientific:
Let’s do the assembly
It goes to objc_initWeak, why is that? Because in LLVM symbols are bound. Just like before super, a specific identifier will be found.
objc_initWeak
/** * initializes a new weak pointer to an object location. * It will be used for The following code: * * (The nil case) * __weak ID weakPtr; * (The non-nil case) * NSObject *o = ... ; * __weak id weakPtr = o; * * This function is not thread-safe for concurrency * modification of weak variables. (Concurrent weak cleanup is safe.) * *@param location Address of __weak ptr.
* @param newObj Object ptr.
*/
id
objc_initWeak(id *location, id newObj)
{
if(! newObj) { *location = nil;return nil;
}
return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>
(location, (objc_object*)newObj);
}
Copy the code
storeWeak
static id
storeWeak(id *location, objc_object *newObj)
{
ASSERT(haveOld || haveNew);
if(! haveNew) ASSERT(newObj == nil); Class previouslyInitializedClass = nil; id oldObj; SideTable *oldTable; SideTable *newTable;// Get locks for old and new values.
// Order by lock address to prevent lock order problems.
// If our old values below change, please try again.
retry:
if (haveOld) {
oldObj = *location;
oldTable = &SideTables()[oldObj];
} else {
oldTable = nil;
}
if (haveNew) {
newTable = &SideTables()[newObj];
} else {
newTable = nil;
}
SideTable::lockTwo<haveOld, haveNew>(oldTable, newTable);
if(haveOld && *location ! = oldObj) {SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
goto retry;
}
// Prevent deadlocks between weak reference mechanisms
// And class initialization mechanism to ensure that there is no
// Weak reference objects have uninitialized ISA
if (haveNew && newObj) {
Class cls = newObj->getIsa();
if(cls ! = previouslyInitializedClass && ! ((objc_class *)cls)->isInitialized()) {SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
class_initialize(cls, (id)newObj);
// If this class is finished with +initialize then we're good.
// If this class is still running +initialize on this thread
// (i.e. +initialize called storeWeak on an instance of itself)
// then we may proceed but it will appear initializing and
// not yet initialized to the check above.
// Instead set previouslyInitializedClass to recognize it on retry.previouslyInitializedClass = cls; goto retry; }}// Remove old values, if any.
if (haveOld) {
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
}
// If there is a new value, the new value is assigned
if (haveNew) {
newObj = (objc_object *)
weak_register_no_lock(&newTable->weak_table, (id)newObj, location,
crashIfDeallocating ? CrashIfDeallocating : ReturnNilIfDeallocating);
// weak_register_no_lock returns nil if weak store should be rejected
// Set is-weakly-referenced bit in refcount table.
if(! newObj->isTaggedPointerOrNil()) { newObj->setWeaklyReferenced_nolock(); }// Do not set *location anywhere else. That would introduce a race.
*location = (id)newObj;
}
else {
// No new value. The storage is not changed.
}
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
// This must be called without the locks held, as it can invoke
// arbitrary code. In particular, even if _setWeaklyReferenced
// is not implemented, resolveInstanceMethod: may be, and may
// call back into the weak reference machinery.
callSetWeaklyReferenced((id)newObj);
return (id)newObj;
}
Copy the code
haveOld = nil; oldTable = nil;
haveNew = YES; newTable = newTable = &SideTables()[newObj];
Copy the code
haveNew = YES;
newObj = (objc_object *)weak_register_no_lock(&newTable->weak_table, (id)newObj, location, crashIfDeallocating ? CrashIfDeallocating : ReturnNilIfDeallocating);
Copy the code
Finally return out;
Weak Process Summary
- 1: First of all, we know that there is a really cool guy named sideTable
- 2: Obtain the weakTable weak reference table of sideTable
- 3: Create a Weak_entry_t
- 4: Add referent to weak_entry_t array inline_Referrers
- 5: Expand the weak_table
- 6: Add new_entry to weak_table
Going back to __weak why is 2 printed?
Let’s break it up and assemble it:
As you can see, objc_loadWeakRetained is called
objc_loadWeakRetained
Here we do an obj->rootTryRetain() operation, which follows the retain process we explored earlier;
Why would Apple do that?
Then look at:
That is, weakObjc and objC are independent of each other. After the middle code block, weakObjc points to nil. There is no relationship between objC and objC; WeakObjc simply loads weak references in the table.
It will crash because you can’t find the weak reference table. .