The structure of the class

The structure of the class when it is first loaded from disk into memory is as followsThe first time it’s usedThe dynamically updated part is extracted and storedclass_rw_ext_t

The overall structure of the final class is as follows.roClean memory, from the time it’s loaded, there’s no change,rwIs dirty memory and is used to store dynamic changes

The cache analysis

What is the cache

We print out the contents of cache_t in the LLDB by shifting the address of the pointer. Here is the definition of cache_t. This article removes some unnecessary code

struct cache_t {
    explicit_atomic<struct bucket_t *> _buckets;
    explicit_atomic<mask_t> _mask;
    uint16_t _flags;
    uint16_t _occupied;
    };
struct bucket_t {
private:
    explicit_atomic<SEL> _sel;
    explicit_atomic<uintptr_t> _imp;
    };
Copy the code

Here is the LLDB debugging process,aboutbucket_tStored in the_bucketsIs through thehashValue, where_occupiedI mean it takes up a couple of,

unsigned cache_t::capacity()
{
    return mask() ? mask()+1 : 0; 
}
Copy the code

_buckets = number of buckets -1. To find out how to save the _buckets

The following is a flowchart of the INSERT

LLDB calls the method

When we call methods through LLDB, we may find that the contents of the cache are not what we expected, and LLDB may increase the number of function callsWe call it in our codesetHobby:, is called in LLDBaaaNameIf theinsertIt’s only called twice, so it’s not going to be expanded, so you can see the currentoccupied = 2.mask = 7, indicating that the call is inaaaNameTime to expand the capacity.

The occupied = 4, mask = 7, and then output the contents of the buckets

The content of buckets is found to be extra class and respondsToSelector:, which is added by the LLDB call method. We call two methods through the code, and by the time we get to the third, we will expand, through the following source code

We will findbucketsWill be the last onebucket_ttheIMPSet to point to the first bucket, so when capacity is 4, only three are valid.

Added isKindOfClass & isMemberOfClass

The above results may feel more confused, so on the source coderes1~res4Class methods are calledisKindOfClassisMemberOfClass

First loop TCLS: root metaclass, CLS is NSObjet unequal second loop TCLS: The parent class of the root metaclass is NSObject equals CLS so res1 is YES analyze res2 self->ISA is the root metaclass, not equal to NSObject analyze res3 the first time TCLS: MLPerson metaclass, not equal to TCLS the second time: The parent class of MLPerson metaclass is the root metaclass, which is not equal, and the res3 metaclass is not equal to res4 analysis self->ISA is MLPerson metaclass, which is not equal to MLPersonCopy the code