preface

In the last article, ios fundamentals 03– Isa bitmap & Class structure exploration carried out an overall analysis of the class structure process. Today we carry on some supplement to the class structure, as well as the question in the process to explain, so the knowledge point is scattered

WWDC2020 about class optimization

Advancements in the Objective-C Runtime

Dirty Memory vs. Clean Memory

Clean Memory

  • clean memoryMemory that does not change after loading
  • class_ro_tBelong toclean memoryBecause it isread-onlyDoes not modify its memory
  • clean memoryYou can do thatremoveTo save more memory space if you need itclean memoryThe system can be reloaded from disk

Dirty Memory

  • dirty memoryMemory that changes while the process is running
  • The class structure becomes as soon as it is useddirty memoryBecause the runtime writes new data to it. Such as creating a new method cache and pointing to it from the class, initializing class-related subclasses and superclasses
  • Dirty memory is the main reason that class data is split into two parts

Dirty Memory vs. Clean Memory

Dirty memory is much more expensive than clean memory, and it must exist for as long as it runs. By separating out data that will not change, most of the class data can be stored in clean memory, which Is what Apple is pursuing

Class_rw_t optimization

When a class is first created and used,runtimeIt is allocated additional storage capacity, which is allocated at runtimeclass_rw_t.class_rw_tUsed forRead writeData, what’s stored in this data structure is onlyThe runtimeTo generate new dataAll classes are passedfirstSubclassandnextSiblingClassPointer implementedThe treeStructure, which is iterated as it runsAll classes currently in use

Question 1: As can be seen from the figure aboverwroThere areMethodsmethodsProtocolsagreementPropertiesProperties. Why is that?

  • Because they can be inThe runtimeMake the change
  • whencategoryWhen loaded, it can be added to a classAdd new methods
  • throughruntimeAPI manual class addedattributeandmethods
  • class_ro_tread-onlySo we need to be in theclass_rw_tTo keep track of these things

Problem 2: The class_rw_T structure occupies a lot of memory in the system. How to optimize the structure?

  • We are inrwThese things are needed in part because they areThe runtimeIt can be modified, but about 90% of classes do not need to be modified and only inswiftYou would use this indemangledNameField, butswiftClasses also don’t need this field most of the time, except to access themObjective-CName is required. So we can remove those parts that we don’t usually useclass_rw_ext_tThe inside.

conclusion

Class_rw_t optimization is basically stripping out the parts of class_rw_t that are not commonly used. If you need this part, you allocate one from class_rw_ext_t(extended record) and slide it into the class for it to use

Whether a class method is in a metaclass

Object (instance) methods are stored in a class, which is a class object relative to a metaclass. The class method in an object == the instance method of a class object, and the instance method of a class object should be in a metaclass

For example, LGPerson *person’s minus method [Person sayHello] is stored in LGPerson where LGPerson is relative to LGPerson’s metaclass (XXX instead) XXX object, the + + method in the *person init == LGPerson’s minus method init, so the XXX object’s minus method should be in XXX

Add instance methods and class methods with the same method name to a custom class, and compile and run without error. If it’s all in a class, then the compiler is going to have a problem, because it can’t tell which method I need, so we assume that the class method is not in the class, so maybe it’s in the metaclass. We explained the principle in the last article in Meta Class, so let’s verify it in code.

Class_getInstanceMethod gets the instance method of the class

Write a piece of code in it

  • sayClassMethodAs a class method
  • sayInstanceMethodIs the object method

It can be seen thatclasstheInstance methodsThere aresayInstanceMethodmethodsThe metaclasstheInstance methodsThere aresayClassMethodmethods

Class_getClassMethod gets the class method of the class

It can be seen thatclasstheClass methodThere aresayClassMethodmethodsThe metaclasstheClass methodThere aresayClassMethodmethods

conclusion

  • Instance methodsinclass,Class methodinThe metaclassIn the
  • Automatically generated by the compilerThe metaclassThe purpose is to storeClass method

Question about 2 apis

sayInstanceMethodHow theLGPersonClass where is it not found

Source code analysis:class_getClassMethodIs to go toThe metaclassThe lookupInstance methods. Print the resultsayInstanceMethodThere is noThe metaclassMedium, not found.sayClassMethodinThe metaclassIn, can be found. It doesn’t exist at the bottomClass method, it is inCommon methodsDo a lookup.

class_getMethodImplementationImp1 and IMP4 should be nil

IMP class_getMethodImplementation(Class cls, SEL sel) { IMP imp; if (! cls || ! sel) return nil; lockdebug_assert_no_locks_locked_except({ &loadMethodLock }); imp = lookUpImpOrNilTryCache(nil, sel, cls, LOOKUP_INITIALIZE | LOOKUP_RESOLVER); // Translate forwarding function to C-callable external version if (! imp) { return _objc_msgForward; } return imp; }Copy the code

Imp1 and IMP4 have the same address, imp1 and imp4 have the same address

The difference between member variables, instance variables, and attributes

Member variables

  • inObjective-CVariables written inside curly braces in a class declaration are called member variables, for exampleint a.NSObject *obj
  • Member variables are used toInside the classVariables that do not need to contact the outside world
@interface LGPerson : NSObject { NSObject *objc; // NSString *nickName; // Member variable}Copy the code

The instance variables

  • The data type of the variable is notBasic data typesAnd a class is called an instance variable, for exampleNSObject *obj
  • Member variablescontainsThe instance variables

The difference between member variables and attributes

  • Member variables: There are no other operations at the bottom that are just variablesThe statement
  • Properties: the system automatically adds them to the bottom layer_ Attribute name variableAnd generate at the same timesetterandgettermethods

SEL and IMP relationship

  • SEL: method number SEL corresponds to the table of contents name of the book (outline of page number)
  • IMP: function pointer address IMP is equivalent to the page number of the book (page address)

The low-level implementation of setter methods

When exploring the difference between attributes and member variables, I found that setter methods of attributes are either implemented through objc_setProperty, or directly memory offset to obtain the address of variables, and then assign values can be obtained through exploring LLVM

Copy void objc_setProperty(id self, sel _cmd, ptrdiff_t offset, id newValue, BOOL atomic, Bool Copy = (shouldCopy &&shouldcopy! = MUTABLE_COPY); Bool mutableCopy = (shouldCopy == MUTABLE_COPY); reallySetProperty(self, _cmd, newValue, offset, atomic, copy, mutableCopy); }Copy the code

It turns out that he actually called reallySetProperty

static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, Bool mutableCopy) {if (offset == 0) {// change ISA 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; // Reference count +1 newValue = objc_retain(newValue); } // Atomically related if (! atomic) { oldValue = *slot; *slot = newValue; } else {// lock spinlock_t& slotlock = PropertyLocks[slot]; slotlock.lock(); oldValue = *slot; *slot = newValue; slotlock.unlock(); } // reloase oldValue reference count -1 objc_release(oldValue); }Copy the code

conclusion

  • copyAttributes used to modifyobjc_setPropertyOther attributes are usedMemory migrationimplementation
  • Apple doesn’t write all of the setter methods in the bottom layer, because the bottom layer can be very cumbersome to change if it needs to be maintained. To make aAdapter middle layerThe role of the middle layer is to provideThe upper setterCall, middle tier pairProperty modifierTo judge the different process, call the bottom method implementation

The advantage of the middle layer: the change of the bottom layer is not affected by the change of the top layer is not affected by the bottom layer

The underlying implementation of getter methods

When exploring the difference between attributes and member variables, the value is basically obtained by obtaining variable address through memory offset. It’s only implemented in a few cases with objc_getProperty as you can see by exploring LLVM

conclusion

  • ARC: Atomic + copy modified properties are implemented using objc_getProperty, and other properties are implemented using memory offset

  • MRC: Atomic + retain modified properties are implemented using objc_getProperty, and other properties are implemented using memory offset