This is the 15th day of my participation in the August More text Challenge. For details, see: August More Text Challenge
1. Why ro, RW, rWE
- Ro belongs to CleanMemory. The memory space is determined upon compilation. It is read-only and does not change the content space after loading
- Rw belongs to dirtyMemory. Rw is a run-time structure. It can be read and written.
- Rwe is the equivalent of extra information for classes, because very few classes actually change their content during actual use, so rWE is used to avoid resource consumption.
Ro is copied into RW because classes can add methods at runtime, and programmers can dynamically add methods or properties to classes. Ro is read-only, so you need to keep track of these things in RW. Not every class will be added dynamically, so if this piece of memory is written in RW, it will affect dirty memory, so put these things in RWE.
2. cls->data()
Where does ro come from in realizeClassWithoutSwift? Find the place where the value was assigned.
It is found that an address pointer is returned, and Pointers can be valued and strong-rolled. We’re going to get the address pointer from macho, and we’re going to assign to class_ro_t.
3. extAllocIfNeeded & attachCategories
Go back to methodizeClass and see that rwe is equal to rw->ext().
Click in to look at the implementation and find the following method extAllocIfNeeded, if there is this method there will be rWE.
Look for extAllocIfNeeded in the source code and find the call in attachCategories. When you add a category, rWE must have a value. There are also calls for class_setVersion, addMethods_finish, class_addProtocol, _class_addProperty, and objc_duplicateClass. This means that rWE creation takes place only when processing is done at run time.
Now let’s look at attachCategories, because we need to look at how the categories are written to the classes. Search for attachCategories in the source code and find calls in attachToClass, load_categories_NOLock.
Load_categories_nolock is unfamiliar, attachToClass is seen in methodizeClass, so take a look at attachToClass. And you see that there’s a place to judge the Previously to see if we’re going to call attachToClass.
Let’s see where previously came from. Discovery is the second parameter of methodizeClass.
Next search for the call to methodizeClass. Found in realizeClassWithoutSwift.
Again, we see that Previously is the second parameter to realizeClassWithoutSwift.
Next, look for the call to realizeClassWithoutSwift. Notice that the second argument passed is nil, so that previously is an alternate argument for internal tuning purposes. Now that the previously nil function is not going to go in, it’s just going to call attachToClass.
Now let’s look at attachLists inside attachCategories. Look at the shortest place in the middle. So what we’re saying here is that if we don’t have a list and we have one element attached to a list, then the list is going to be a one-bit array with that element.
Let’s look at the else case below. What we do here is create a new array with count as new list.count + 1 (or 0 with oldList), put the entire array at the end of the new array, and then add the elements from the array starting at the head of the new array.
In the last part, what we do here is we create an array with count as the number of oldList counts plus the number of addedList counts. We add the oldList elements from I +addedCount bits. Then add the addedList in turn from the beginning.
4. Lazy loading of categories
Before we said that classes have lazy loading and are controlled by the load method, can classes also have lazy loading? And is there a relationship between class lazy loading and class lazy loading? Let’s explore.
Both classes and classifications implement LOAD
To look at the case where both classes and categories implement load, type a breakpoint at attachCategories and run.
When you run it, you will find that you are in the non-lazy loading area of _read_images
Then come to realizeClassWithoutSwift.
And then we go inside methodizeClass and we call attachToClass.
And then we go down to attachCategories
So the call process is as follows: map_images -> map_images_nolock -> _read_images -> readClass -> realizeClassWithoutSwift -> methodizeClass -> attachToClass -> load_images -> loadAllCategories -> load_categories_nolock -> load_categories_nolock -> attachCategories -> attachLists
Classes implement load and classes do not implement load
When I remove the load method for the classification and run it again, I find that the attachCategories method is not implemented.
Classes do not implement load and classes implement load
When I remove the load method for the classification and run it again, I find that the attachCategories method will not be implemented as in the previous case.
Neither class nor classification implements load
When I run it, I find that it goes directly into main.
5. Classification loading in four different situations
Both classes and classifications implement LOAD
We implement the load method for the class and the class, we run it, we go to realizeClassWithoutSwift and we type ro to see if the class data has been loaded, if it has, then the class has been loaded in realizeClassWithoutSwift, Otherwise it’s after realizeClassWithoutSwift. After output all baseMehtods, there is no classification method, so the classification has not been loaded.
Next look at load_categories_nolock and output cat to see that this is the category we created.
Look at the output CLS and see that it’s actually LGPerson.
Next, go down to attachCategories, where CLS ->isRealized() is true because CLS was loaded at read_images.
If you look at attachCategories, you see the mList data structure, and the count is 2, which is the two methods in the category.
As you go down, you put the mlist at the end of the mlist.
Go down, skip the properties and protocols in the middle, and you’re here. And you can see here that the prepareMethodLists call is sorted, and then the attachLists call is added to RWE’s methods call.
Go in and look at attachLists. We see here that addedLists is a second-level pointer.
And then you go down, and you see else.
Printouts are all Pointers that are stored.
So let’s take a look at the output and see that this addedList[0] is storing the categories
Classes do not implement load. Classes implement LOAD
AttachCategories are not entered, that is, no categories are loaded, but classes are loaded.
The class was forced to open. The classification is implemented for the main class, so to implement the classification, we must first implement the class. RealizeClassWithoutSwift (); realizeClassWithoutSwift (); realizeClassWithoutSwift ();
Classes implement load. Classes do not implement load
AttachCategories are not entered, that is, no categories are loaded, but classes are loaded.
RealizeClassWithoutSwift (); realizeClassWithoutSwift (); realizeClassWithoutSwift ();
Neither class nor classification implements load
When I run it, I find that it is directly inside the main function, both of which are lazily loaded.
RealizeClassWithoutSwift (); realizeClassWithoutSwift (); realizeClassWithoutSwift ();
That is, when neither class nor classification implements load, both are lazily loaded and initialized when the class first receives the message. But the class and class loading are already in the data.
6. Loading of multiple categories
All classes implement LOAD
Add a category and run. See that both categories are loaded.
The following process is the same as the loading of a single category, but the attachLists are different. So that’s where the categories are loaded.
Not all classes implement load
After running it, it’s all loaded.
ProcessCatlist is a block, called below.
Load_categories_nolock is called by loadAllCategories, loadAllCategories is called by load_images, And decided by didInitialAttachCategories and didCallDyldNotifyRegister don’t call, didInitialAttachCategories default is false, and when loadAllCategories after the call, DidInitialAttachCategories to true, so they only call once.
So the reason it can be loaded into a category is that it is read from macho by catList.
In general, Mach loads the entire data structure, and when load is called, it scrambles the algorithm to do the calculation, so load takes time. Normally, classes and classifications are loaded in Macho.