Reference counting technology for Android C + + framework Layer
The use of pointers in C + + is a headache, one is often forget the free pointer, causing memory leaks, the other is a wild pointer problem: Access to the already free pointer. A considerable part of the program's debug work is spent here. With reference counting in Android to automatically manage the lifetime of a pointer, dynamically requested memory is automatically freed when it is no longer needed (a bit like Java garbage collection), without the programmer explicitly using delete to free the object, or considering whether an object has been freed elsewhere. So that the program writing work to alleviate a lot, and the stability of the program greatly improved.
Android provides reference counting technology, mainly through the Refbase class and its sub-class SP (strong pointer) and WP (weak pointer) implementation, the specific principles and details will not say, you can see the deep understanding of Android: Volume 1, The words are still quite clear.
Problem with reference counting
Nothing is omnipotent, the reference counting problem in Android C + +, like Java, does not completely avoid memory leaks, there is another problem is the performance (overhead) problem is also very prominent, this article does not say.
Using the Android SP pointer, you cannot say that you do not need the programmer to care about the details of the pointer. Usually due to poor design or use, it is more likely to lead to memory can not be recycled, that is, memory leaks, and may even lead to unknown wild pointer problems. At this point, the memory usage problem, because of its more deceptive and covert, often more difficult to detect and debug.
Circular reference and its solution
A common Java memory leak problem exists in C + + in smart pointer management methods that use reference counting. One of the most common of the strong pointer references in Android is the problem of circular referencing of strong pointers. This is another problem that programmers can easily make: when the programmer's understanding of the strength and weakness of pointers is not very deep, it is assumed that a strong pointer is used, and the system is automatically retracted based on the reference count.
A circular reference is a strong pointer to object A, a reference to object B, and a strong pointer in object B, which refers to object A; so that A and B are interlocked. A object that releases a reference to a B object is when it is being refactored, and the premise of a destructor collection is that the A object is not referenced, then the B object is released first, and the B object is freed by the A object. So neither a nor B can be released, which creates a memory leak.
We can write a program to see the leaks.
First define a class, which is assumed to be called Bigclass:
namespaceandroid{classBigclass: PublicRefbase { Public: Bigclass (Char*name) {strcpy (mname, name); ALOGD ("Construct:%s", Mname); } ~Bigclass () {ALOGD ("Destruct:%s", Mname); } voidSetstrongrefs (sp<bigclass>b) {SpB=b; } Private: SP<Bigclass>SpB; Charmname[ -]; };}
This class is very simple, with only one SP pointer and one name member. Examples of circular references:
voidTeststrongcrossref () {SP<Bigclass> A =NewBigclass ("Teststrongclassa"); SP<Bigclass> B =NewBigclass ("TESTSTRONGCLASSB"); A-setstrongrefs (B); B-setstrongrefs (A);}intMain () {ALOGD ("Start teststrongclasses."); Teststrongcrossref (); ALOGD ("teststrongclasses should be destructed!!"); return 0;}
The result of the output, as expected, was not released, and the object was leaked:
D/test (1552): Start teststrongclasses. D/test (1552): Construct:teststrongclassad/test (1552): Construct:teststrongclassbd/test (1552): Teststrongclasses should be destructed!!
To solve this problem, Android has introduced weak pointers, and weak pointers do not control the life cycle of the referenced objects by reference counting, which eliminates the reference loop problem in the previous example and makes the problem resolved. We have slightly modified the above class to add a weak reference to the interface:
namespaceandroid{classBigclass: PublicRefbase { Public: Bigclass (Char*name) {strcpy (mname, name); ALOGD ("Construct:%s", Mname); } ~Bigclass () {ALOGD ("Destruct:%s", Mname); } voidSetstrongrefs (sp<bigclass>b) {SpB=b; } voidSetweakrefs (sp<bigclass>b) {WpB=b; } PrivateSP<Bigclass>SpB; WP<Bigclass>WpB; Charmname[ -]; };}
Let's test it and replace the strong pointer in the previous example with a weak pointer, what happens:
void Testweakcrossref () {SPnew bigclass ("testweakclassa"); SPnew bigclass ("testweakclassb"); A-setweakrefs (B); B-setweakrefs (A);}
Output Result:
2889 ): Start testweakclass. D2889): Construct:testweakclassad2889): CONSTRUCT:TESTWEAKCLASSBD 2889): DESTRUCT:TESTWEAKCLASSBD2889): Destruct:testweakclassad2889) : Testweakclass should be destructed!!
After the Testweakclassa and TESTWEAKCLASSB are out of scope in objects A and B, there is no strong reference, and two objects are released, which is expected.
Here the referential relationship between Testweakclassa and TESTWEAKCLASSB is all weak, so the life cycle between the two is irrelevant, where the sp<bigclass> objects A and B are used to create a generic stack object Bigclass A, The life cycle of Bigclass B is the same.
Android, the most commonly used is definitely not the above two:
- The powerful quote-------------it is absolutely forbidden to bind each other to death.
- Weak weak references--unrelated, each tube life and death. This is of little use to automatically manage object lifecycles using reference counting.
The most commonly used is the strong and weak reference relationship. Strong and weak references need to have a subordinate relationship, the specific class is to use the SP reference, which is used WP reference, to see the logic of the design.
Test Example:
void Testcrossref () {SPnew bigclass ("testnormalclassa"); SPnew bigclass ("testnormalclassb"); A-setstrongrefs (B); B-setweakrefs (A);}
Output Result:
D/test (2889): Start TEST Normal pointer Reference. D/test (2889): Construct:testnormalclassad/test (2889): Construct:testnormalclassbd/test (2889): Destruct:testnormalclassad/test (2889): Destruct:testnormalclassbd/test (2889): TEST Normal pointer Reference should be destructed!!
In this case, the circular reference is eliminated without a memory leak issue. Compared with the example of a weak weak reference, here Testnormalclassb's destructor is Testweakclassa, and TESTWEAKCLASSB's life cycle is controlled by Testweakclassa, only Testweakclassa-destructor , TESTWEAKCLASSB will not be deconstructed. (The example of weak weak reference above shows that in the case of no intervention, it should be TESTWEAKCLASSB first)
For the use of strong and weak pointers, the use of weak pointers is a need to pay special attention, the weak pointer to the object, may have been destroyed, before use by the promote () method to detect, detailed information can refer to "in-depth understanding of Android"
Wild pointer problem
The issue of strong and weak references, I believe most Android programmers understand that the main thing to emphasize here is: Use caution, accidentally may be wrong, for example:
We add another constructor to the bigclass we just defined:
Bigclass (charChar * other ) { strcpy (mname, name); ALOGD ("Construct another:%s", mname); Setweakrefs (this); }
This constructor is used to construct the WP type member variable in this object, that is, the WP pointer points to itself, which is allowed.
In writing a test case:
void Testcrash () { SPnew bigclass ("testcrasha"" Testcrash"); SPnew bigclass ("testcrashb"); A-setweakrefs (B); B-setweakrefs (A);}
Output Result:
D/test (3709): Construct another:testcrashad/test (3709): Destruct:testcrashad/test (3709): Construct: Testcrashbd/test (3709): DESTRUCT:TESTCRASHB
There seems to be no problem, the program did not collapse it?
No crashes, that's lucky, because this test code and context is too simple. We see the output will know: TESTCRASHB object construction, Testclassa has been deconstructed!!!!
In other words, a object, after its creation, is immediately extinct, the Testcrash () method in the operation of a object pointed to, are the wild pointer!!!
Why is there a wild pointer? The problem is in the constructor Bigclass (Char *name, char * other) that you just defined.
Setweakrefs (this);
Here this is a bigclass * type, so that in the argument stack when the need to construct a temporary sp<bigclass> strong pointer object, after the call is completed, the object is refactored. The SP object is constructed from the SP's sp<t*> constructor.
Here we look at the construction and destruction of this temporary SP object:
After the construction is complete: New Bigclass object Testcrasha, this refbase subclass object, with a strong reference count of 1 (from Initial_strong_value to 1)
After the destruction is complete: The SP's destructor reduces the Bigclass object pointer (that is, the object Testcrasha, which is also the object pointed to by this pointer here), which is reduced from 1 to Initial_strong_value, When the reference count of an object is reduced to initial_strong_value, the delete operation of the Bigclass object is triggered, and the object pointed to by the this pointer is also refactored.
Here, the constructor is to delete the constructed object, more difficult to imagine it! It is interesting to be able to verify the look, modify the constructor function just now:
Bigclass (charChar * other ) { alogd ("start Construct Another:%s, " , mname); strcpy (mname, name); Setweakrefs (this); ALOGD ("end Construct Another:%s,", Mname); }
See if the destructor is between start and end. Run for a while and you'll have unexpected print:)
Here's a rule: you can never use a local short-scope SP pointer reference before creating a Refbase object that has not yet been referenced by a long-scoped SP object.
Suggestions
There's nothing to suggest, and figuring out the design intent and working principle is good for debugging and writing code.
Reprint:http://blog.csdn.net/freshui/article/details/9049193#
Android reference counting (strong and weak pointers) technology and some problems