This is the sixth day of my participation in Gwen Challenge

WWDC 2020In aboutruntimeThe optimization of the

WWDC 2020 Viewing address

In WWDC 2020, Apple optimized the Objective-C Runtime to greatly improve memory usage

Class data structures changesTo optimize the

Optimizations of data structures that the Objective-C Runtime uses to track classes

On disk, the class in our App binary looks like this

First, the class object itself contains the most frequently accessed information: Pointers to metaclasses, superclasses, and method caches. It also has a pointer to more data to store additional information. Class_ro_t:

Ro stands for read-only and contains information like class names, methods, protocols, and instance variables. Swift and Objective-C classes share this infrastructure, so no Swift class has this structure

When classes are first loaded from disk into memory, they start out this way, but as they are used, they change. To understand these changes, we must first understand the difference between clean and dirty memory

clean memory

Memory that does not change after loading. Class_ro_t is clean memory because it is read-only

dirty memory

Dirty memory refers to memory that changes while the process is running. Class structures become dirty memory when used because the runtime writes new data to them. For example, create a new method cache and point to it from the class;

Dirty memory is much more expensive than clean memory and must exist as long as the process is running; Clean Memory can be removed to save more memory, because the clean memory system can be reloaded from disk if you need it. MacOS can swap out dirty memory, but iOS doesn’t use swap, so dirty memory is expensive on iOS. Dirty memory is why a class is divided into two parts, the more data that can be kept clean, the better; By separating out data that never changes, you can store most of your class data in clean memory.

While this data is enough to get us started, the runtime needs to keep track of more information about each class, so when a class is first used, the runtime allocates it additional storage capacity class_rw_T for read-write data

In the class_rw_t data structure, we store new data First Subclass and Next Sibling Class that can only be generated at run time; For example, all classes are linked into a tree structure by using First Subclass and Next Sibling Class Pointers. This allows the runtime to traverse all classes currently in use, which is very useful for invalidation of method caching; But why do Methods, Properties, and Protocols still exist in class_ro_t when it is read-only? Because they can be changed at run time, when a Category is loaded, it can add new methods to the class, and developers can add them dynamically using the runtime API. Because class_ro_t is read-only, we need to keep track of these things in class_rw_t; However, the result of this is that we can take up quite a bit of memory. There are many classes in use on any given device. Apple has measured the entire system on the iPhone, and it shows that about 30 megabytes are stored in the class_rw_T structure.

Note that we need these things for read-write data because they can be changed at run time, and Apple found that about 10% of the next classes actually changed their methods by checking their use on the actual device; The Demangled Name field is only used by the Swift class, and it is not required by the Swift class unless they are asked for their Objective-C name. Therefore, we can remove the parts that are not used. This reduces the size of class_RW_t by half

For classes that do require additional information, we can assign one of these extension records. And add it to the class for its use

About 90% of our classes never need this extended data, and this system-wide savings is about 14MB of memory that we could use in more efficient ways, like storing our App’s data

$ heap Mail | egrep 'class_rw|COUNT'
Copy the code

The above command helps us to see how many class_rw_t types are used in our mail App. In fact, only 10% of them need to use this extended information. Based on this, we can easily calculate the memory savings from this change: This is the size of halving type, so if we minus from the figure we must be assigned to expand the types of memory, we can see that we saved about a quarter of one million bytes, and that is only for mail App, if any, be performed within the system extension of dirty memory, this is the real save memory

To be continued

Relative method listsTo optimize the

Optimization of objective-C method lists

Tagged pointer format changesTo optimize the

class_rw_t

class_ro_t

class_tw_ext_T