Memory management in both Objective-c and Swift languages is based on reference count "reference counting", and reference counting is a simple and effective way to manage the lifecycle of an object. Reference counts are divided into manual reference counts "arc:automaticreference counting" and automatic reference counts "mrc:manual Reference counting", now all with ARC, but we still need to know about MRC.
1. What is the principle of reference counting?
When we create a new object, his reference count is 1;
When a new pointer points to the object, his reference count is added by 1;
When an object is associated with a pointer that no longer points to him, his reference count is reduced by 1;
When the object's reference count is 0 o'clock, which means that the object is no longer pointed to by any pointers, then we can destroy the object and reclaim the memory.
Because reference counting is simple and effective, Microsoft's com"component Object model", c++11 (based on reference-counting smart pointers, in addition to Objective-c languages share_ PRT) and other languages also provide memory management based on reference counting.
As an example:
New project, Xcode the default is ARC, we use MRC for the "appdelegate.m" file, for the following configuration:
Select the target project, and then under "compile sources" of "build phases" the "appdelegate.m" file configuration compiler parameter "compiler value is flags"
-(BOOL) Application: (UIApplication *) application didfinishlaunchingwithoptions: (Nsdictionary *) launchOptions {
NSObject *objo = [NSObject new];
NSLog (@ "Reference Count:%lu", (unsigned long) [Objo Retaincount]); 1
nsobject *OBJB = [objo retain];
NSLog (@ "Reference Count:%lu", (unsigned long) [Objo Retaincount]); 2
[Objo release];
NSLog (@ "Reference Count:%lu", (unsigned long) [Objo Retaincount]); 1
[Objo release];
NSLog (@ "Reference Count:%lu", (unsigned long) [Objo Retaincount]); 1
[objo setvalue:nil forkey:@ "test"];//Zombie object, sending a message to the wild pointer will give an error (exc_bad_access) return
YES;
Xcode does not monitor zombie objects by default, we configure them to open, and then we can see specific tracking information:
You can also open a "instruments" toolset by selecting the "profile" under "product". Then select "zombies", then click the lower right corner of the "choose" button to enter the detection interface, then click on the upper left corner of the "record" red dot button to start detection.
1.1 The above example, why is the last time to get through the Retaincount value of 1, instead of 0?
Because the object's memory has been reclaimed, we send a retaincount message to a reclaimed object, and his output is indeterminate, and if the object's memory is reused, it can cause the program to crash.
And when the last release was performed, the system already knew that it was going to reclaim the memory, and there was no need to reduce the retaincount by 1, since the object would be recycled regardless of minus 1, and the memory area (including the Retaincount value) would have no meaning after it was recycled. Reducing the Retaincount by 1 to 0 reduces the memory operation once and accelerates the collection of objects.
1.2 What are zombie objects, wild pointers, empty pointers?
Zombie objects: Objects that occupy memory that has been reclaimed, and zombies cannot be reused.
Wild pointer: A pointer to a zombie object (not available memory), and sending a message to the wild pointer will give an error (exc_bad_access).
Null pointer: There is no pointer to any object (stored nil, NULL), sending a message to the null pointer does not report an error; A classic use scenario for a null pointer is to obtain the server API data in the development, the conversion field pointer is null pointer, avoid sending a message error.
2. Why do I need reference counting?
From the simple example above, we do not see the real usefulness of reference counting, because the object's lifecycle is only within one method. In a real-world scenario, we use temporary objects within a method, and usually do not need to modify his reference count, just to destroy the object before the method returns.
However, the real use of reference counting is in object-oriented programming architectures, where data is passed and shared between objects.
As an example:
If object a generates an object o, you need to call a method of object B, passing the object o as a parameter.
In the absence of a reference count, the principle of general memory management is "who is applying for release", so object A needs to destroy object O when object B no longer needs object o. But object B may temporarily use object o, you can also feel that he is important, set him as a member of his variable, in this case, when the destruction of object o is a problem.
There are two ways of doing this:
(1) object A, after calling a method of object B, destroys the Parameter object o immediately, then object B needs to copy the object o one, generating another object O2, and managing the object O2 lifecycle. But one big problem with this approach is that he brings in more memory applications, replication, and release work. The object that could have been reused, because it was not convenient to manage his life cycle, simply destroyed him and reconstructed a similar one, which really affected performance.
(2) Object A is responsible for generating object o, and then object B is responsible for the destruction of Object O. If object B only temporarily uses object o, it can be destroyed immediately after use, if object B takes a long time to use object o, do not destroy him. This approach seems to solve the problem of object duplication, but he strongly relies on the combination of a and B two objects, and code maintainers need to remember this programming convention explicitly. Moreover, because object O is generated and released in different objects, his memory management code is scattered among different objects, and management is laborious. If the situation is more complicated at this time, for example, object B needs to pass the parameter object O again to object C, then the object cannot be managed by object C in Object C. So the complexity of this approach is higher and less desirable.
The presence of reference counts is a good solution to this problem, in the process of passing the Parameter object O, which objects need to use him for a long time, add his reference count to 1, and subtract 1 from the use. All objects adhere to this rule, and the lifecycle management of an object can be completely handed over to the reference count. We can also easily enjoy the benefits of shared objects.
2.1 What is circular reference "reference cycles" problem, how to solve it?
Reference count This memory management method is simple, but one flaw is that he cannot automatically solve the problem of circular references.
As an example:
Object A and Object B refer to each other as their own member variables, only the reference count of their member variables is reduced by 1 when they are destroyed, because the destruction of object A and object B is dependent on each other, which causes what we call a circular reference problem.
Circular references can result in situations where the resources still cannot be released, even if no pointers are available to the outside world to access them.
There are two main ways to resolve circular reference problems:
(1) Clearly know where there is a circular reference, a reasonable opportunity to actively disconnect a reference in the ring, so that the object can be recycled. This method is not commonly used because he relies on the developer's own manual explicit control, which is equivalent to returning to the memory-management age where "who is applying for release".
(2) Use weak reference "weak reference","weak""__weak" type, this method is commonly used. A weak reference does not increase his reference count, although it holds the object. A classic use scenario for weak references is the principal-agent "delegate" protocol model.
Are there any tools in the 2.2 Xcode to detect circular references?
A "instruments" toolset in Xcode can easily detect circular references.
As an example:
-(void) viewdidload {
[super viewdidload];
Nsmutablearray *marrfirst = [Nsmutablearray array];
Nsmutablearray *marrsecond = [Nsmutablearray array];
[Marrfirst Addobject:marrsecond];
[Marrsecond Addobject:marrfirst];
}
You can select the "profile" under "product" to open the "instruments" toolset.
Then select "leaks", then click the lower right corner of the "choose" button to enter the detection interface, then click on the upper left corner of the "record" red dot button to start detection.
3. Memory management of Core Foundation objects
ARC is a compiler attribute, not a run-time attribute, not a garbage collector "gc".
ARC solves 90% of memory management problems in IOS development, but another 10% of memory management issues are needed by developers themselves, primarily in the context of interacting with the underlying core Foundation objects, where the underlying core Foundation objects are not managed by ARC So you need to maintain the reference count of these objects yourself.
In fact, the Cfretain and Cfrelease methods used by the Core Foundation object can be considered equivalent to the retain and release methods of the Objective-c object, so we can do similar management in the MRC way.
3.1 in ARC, in what way can the Core Foundation object be converted to a Objective-c object?
The conversion process is actually telling the compiler how the object's reference count is adjusted.
Here we can use bridging "bridge" related keywords for conversion work, the following is the description of these (double underscore) keywords:
(1) __bridge: Only do type conversion, do not modify the reference count of related objects, the original Core Foundation object when not in use, you need to invoke the Cfrelease method.
(2) __bridge_retained: After type conversion, the reference count of related objects plus 1, the original Core Foundation object when not in use, you need to invoke the Cfrelease method.
(3) __bridge_transfer: After type conversion, the reference count of related objects is given to ARC management, and the original Core Foundation object does not need to invoke the Cfrelease method when it is not in use.
According to the specific business logic, we use the above three kinds of conversion keywords rationally, we can solve the problem of the relative conversion between the core Foundation object and the Objective-c object.