I have one or two weakreferences in my program.
Just for example:
ClassX myClassX= new ClassX(); //Line 1
WeakReference<ClassX> myWeakClassX = new WeakReference<ClassX>(myClassX); //Line 2
if(myWeakClassX.get() != null) // Line 3
{
//do something with reference //Line 4
}
My question:
How is it ensured that when at line 3 myWeakClassX.get() has a valid reference to an Object, it is also valid at line 4? I can imagine that if you are really unlucky, the GC does his job exactly "between" line 3 and 4. Please bear with me, because i'm relatively new to Android/Java..
Thanks for any explanation.
In Java, first thing to understand is Garbage Collector reclaims memory from objects which are eligible for garbage collection
Question is how is the eligibility defined ?
eligibility is decided based upon which kind of references are pointing to that object.
Why we need Weak Reference ?
If you create a Strong reference to an object, the object cannot be garbage collected. Whereas, A weak reference, simply put, is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself.
Issue here
Weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the class) that myWeakClassX.get() suddenly starts returning null.
What is the other option ?
Soft Reference
You use a SoftReference when you want the referenced object to stay alive until the host process is running low on memory. The object will not be eligible for collection until the collector needs to free memory. Loosely stated, binding a SoftReference means, "Pin the object until you can't anymore."
This way myWeakClassX.get() will not be null.
Examples of where we can use ?
In any secondary threads where you create a reference to the activity.
WeakReference weakActivity;
//In AsyncTask onPostExecute Method
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
If you can referring to an Activity context elsewhere, you can use Weak reference.
While handling bitmap resources in imageview in another thread
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
If you are creating any Hashmap or any widget to hold any data, you can use Weak reference. http://developer.android.com/reference/java/util/WeakHashMap.html
Usage is unlimited. It is up to the developer to utilize it at right places.
You are correct that during line 3 and 4 the get() operation can return null, as it is supposed to do. You can always copy the reference you get from get() operation into a variable (thus making it strong again) and use it within the if block safely. Because you still have a strong reference, the object will not be garbage collected.
A simple check for null can be:
if(myWeakClassX.get() != null)
{
ClassX myref = myWeakClassX.get();
if(myref != null) {
//use it
}
}
However in-case of activities, having a strong reference does not guarantee that the activity will not be destroyed and although you have a strong reference that is valid, the activity may throw exceptions when you try to use it as it is destroyed.
Example: If you are keep reference for an activity inside some AsyncTask, the activity might get destroyed (i.e orientation change) before AsyncTask runs. And although you will have a reference to it, you will get exceptions when you try to update UI.
That is where you can create a WeakRefernce to activity inside the AsyncTask and if the get() operation start returning null, you will know that the activity was destroyed by whatever reason and not try to use it.
Related
Example:
Lets say ideally that object is garbage collectable (activity changed orientation and strong reference to object lost) but not yet disposed. So line 2 will return true. Is there any way that object get disposed while execution is on line 3? Or it wait until it finishes?
new Thread {
WeakReference item= new WeakReference(object);
void method(){
2 if(item.get()!=null)
3 item.get().getName();
}
}
If you have strong reference to an object then that object is not eligible for GC.
There is no way strong referenced object will get disposed in code between null check and next line... or any other line as long as you can access that object reference. Only if you set that object reference to null, or you assign another object to that reference, previous object can be garbage collected if there are no other references pointing to it.
On the other hand, when you are dealing with weak references (of any kind) first you have to take strong reference out of weak reference wrapper and then you can safely use that strong reference further on (after you check it is not null, of course). If you don't take strong reference, object in weak wrapper can vanish at any time.
Wrong usage - object can be collected between null check and getName call
if(item.get()!=null)
item.get().getName();
Correct usage - taking strong reference for further processing
Object object = item.get();
if(object!=null)
object.getName();
First of all Garbage Collector does not run on what you think as your proccess's main thread.
When looking from Operating System's prospective, GC may run either in main thread of the virtual machine that runs your application. Or it can run on a new thread.
But from Java prospective, GC does not run on any of your application's thread. The thread that run GC is neither your Java main thread nor a Java thread accessible to you.
From the prospective of your Java code, the main thread and all other thread are stopped (removed from scheduler) while GC runs. This is not always true though. But that is up to the VM implementation. But you must always assume that all your Java threads, including main thread are stopped while GC runs.
So, to precisely answer your question, **
Yes, your week reference can become null in the second line.
**
Your code can get a NullPointerException in line three.
Because line 2 and 3 are two seperate non antomic operations. It is possible that GC can cick in after executing line 2 , stop execution of all your threads, do garbage collection , and then resume all your threads causing a NullPointerException to occur at line 3.
I'm referring to Refbase.h, Refbase.cpp and StrongPointer.h
In the Android implementation of strong pointer, any strong-pointer based object must inherit refbase i.e.
sp<TheClass> theObj // TheClass must inherit from class RefBase
This requirement can be seen in the code for one of sp's methods:
template<typename T> sp<T>& sp<T>::operator =(T* other) {
if (other != NULL) {
other->incStrong(this);
}
if (mPtr != NULL) {
mPtr->decStrong(this);
}
mPtr = other;
return *this;
}
In order for call to incStrong or decStrong to not fail . . . other and mPtr must have inherited RefBase
QUESTION
Why is sp implemented such that the obj that it's managing is required to be a child of RefBase? There's not even a way to enforce this requirement at compile-time or even runtime. (Well maybe if(type()...)
Std library doesn't have such a requirement
...
Upon further thought, is the answer that this provides flexibility?
If yes, how does this provide flexibility?
It saves a memory allocation. When you write:
std::shared_ptr<Foo> pFoo{new Foo(bar)};
pFoo actually has a pointer to a shared data structure (allocated on the heap), which has the reference counters, and the pointer to the actual Foo object. By making objects be derived from RefBase, you can embed the reference counts in the object itself (saving the additional memory allocation).
Interestingly, with C++11 onwards, you can avoid the additional memory allocation by using std::make_shared<Foo> which will do a single memory allocation and construct the shared data structure and the Foo object in it.
The fact there is no compile time checking of the derivation from RefBase is carelessness. m_ptr should have been declared as RefBase *m_ptr, and then operator * (etc) should have done a static_cast to T*. In fact, I would probably have made sp<T> inherit from sp_base which had the comparison operators as public, and the other functions as protected.
Edit
On second thoughts, there is quite a bit of compile time checking. If T doesn't have an incStrong member, the compilation will fail, and it almost certainly won't unless it derives from RefBase. I still think converting a T* to a RefBase* would have been a better check, but the one that is there is probably good enough.
It automatically allows you to create sp from any object implementing RefBase, while for shared pointer you can shoot yourself in the foot while trying to wrap raw pointer into shared one.
So while for shared_ptr you might need this:
http://en.cppreference.com/w/cpp/memory/enable_shared_from_this
for sp you can almost safely pass raw pointer to sp contructor.
I am reading the Xamarin.Android garbage collection docs about helping the GC perform better by reducing referenced instances.
The section begins by saying:
Whenever an instance of a Java.Lang.Object type or subclass is scanned during the GC, the entire object graph that the instance refers to must also be scanned. The object graph is the set of object instances that the "root instance" refers to, plus everything referenced by what the root instance refers to, recursively.
...which I understand.
It then goes to show a custom class inheriting from the standard Activity class. This custom activity class has a field that is a list of strings which is initialized in the constructor to have 10,000 strings. This is said to be bad because all 10,000 instances will have to be scanned for reachability during GC. That I also understand.
The part that I am not clear on, is the recommended fix: it says the List<string> field should be moved to another class that doesn't inherit from Java.Lang.Object and then an instance of that class should be referenced from the activity just like the list was being referenced before.
My question: how does pushing a field deeper into the object graph help the GC when the total number of instances is still 10,000 and the opening paragraph says they will be scanned eventually because the process is recursive?
As a side note, I am also reading up (here) on the SGen GC used by Mono on Android and the object graph traversal process is described as being breadth-first starting with the GC roots. This explains how a 10,000 item list will cause a longer GC pause as each item is checked, but still doesn't explain how moving that list deeper into the graph will help because the GC will eventually scan it as it goes deeper into the graph.
I'll try to explain this the best I can, and I'm nowhere near an expert here so anyone who wants to chime in, please do so.
When we are referring to doing a peer walk, we are locating any roots and traversing the live reference graph to see what is reachable and what is not:
Root Objects:
Objects pointed at by static fields / properties
Objects on the stack of each managed thread
Objects that have been passed into native APIs
Basically you then have to deal with two managed GCs. We'll call them the Xamarin GC and the Android GC for reference.
Xamarin.Android has peer objects which are used to reference the native Java objects known in the Android JVM. They implement a core interface:
namespace Android.Runtime
{
public interface IJavaObject : IDisposable
{
// JNI reference to the Java object it is wrapping.
// Also known as a pointer to the JVM object
public IntPtr Handle { get; set; }
...
}
}
Whenever we have an object with IJavaObject inherited, it will keep a strong reference via that JNI handle above to ensure it is kept alive as long as the managed object is alive.
Think of it this way:
IJavaObject -> IntPtr Handle -> Java Object
In GC terms, it would be represented as the following:
Allocated and collected by Xamarin GC -> GC Root -> Allocated and collected by Android GC
We then have a GC process in Xamarin.Android:
When the GC runs, you can see that it will replace a strong JNI handle with a weak reference and then invoke the Android GC which will collect our Java object. Because of this, the peers are scanned for any relationships to ensure that they are mirrored in the JVM. This keeps these objects from being collected prematurely.
Once this happens, we run the Android GC and when it's finished it will walk through the peer objects and check the weak references.
If an object is gone, we collect it on the C# side
If an object still exists, then we change the weak reference back to a strong JNI handle
Thus this graph needs to be checked and updated each time a GC runs on peer objects. That's why it's much slower for these wrapper type objects because the entire object graph has to be scanned starting at the peer object.
So when there are significant object graphs that our peer object uses, we can help out the GC process by moving the storage of the references outside the peer class. This is usually done by rooting our reference independent of the peer. And since it's not stored as a field, the GC will not try to do a relationship walk on the object graph.
As noted earlier, this isn't a huge issue to worry about until you notice long GCs. You can then use this as a solution.
Image Credit: Xamarin University(https://www.xamarin.com/university)
Is something wrong with this construct in Android?
class A extends Activity {
private Object myObject = new Object();
#Override
protected void onCreate(Bundle savedInstanceState) {
//myObject = new Object();
}
}
Because at some point(s) later I get (sometimes, not reproducible yet) exceptions because myObject is null. I don't know if it's because I have to initialize in onCreate.
Edit: Additional details:
The actual class of myObject is List<Object> (Where Object is a domain specific type)
At some point later in the activity I'm storing myObject as a static field of a "Parameter passer" class and starting other Activity (because I'm avoiding to implement Parcelable. If this is good or bad practice should not be discussed here, unless that's causing my error). In the other Activity I pick up myObject. There it's (sometimes) null.
Edit 2: I don't understand why this object becomes null if I'm storing a reference to it as static field of my parameter passer class (a standalone, dedicated class). That's how garbage collection works, right, it just removes when the objects are not referenced anymore. So since I have a static reference this object should not be removed. According to this thoughts, if they are correct, the problem should be somewhere else.
When you start a new activity your old one goes on the block for possible garbage collection (including any classes instantiated in it, including your parameter passer class), so your object is not necessarily going to be available (which is why you see an intermittent failure.).
I see two option:
1) Pass it along in the bundle with your intent that starts the new activity. As you were trying to avoid this, probably not your best choice.
2) Extend the Application class and store the object in there.
EDIT
I think the accepted answer to this SO Question might fix your issue (and explain what is actually happening).
No. That code is just fine. You can create objects in the constructor.
You may want to check a previous question about it Instance variable initialization in java and the section 3.2.4. Field Defaults and Initializers which basically states that the first case:
private Object myObject = new Object();
is identical to an initialization in the class constructor. (NOTICE onCreate is NOT the constructor).
So, myObject should never be null, except in the case the "new Object()" instruction failed, generating an exception.
Isn't this possible your code is changing the contents of myObject later on the code?
Is it a good idea to specifically set the instance variables to null in onDestroy() callback of the activity? Something like this:
#Override
protected void onDestroy() {
super.onDestroy();
mClassVariable1 = null;
mClassVariable2 = null;
mClassVariable3 = null;
}
If I remember correctly from Java SE, any references that are isolated & not connected to a running program & can be garbage collected anyways. So does this make the above superfluous?
On the other hand, the lifecycle in mobile devices being different, would the above be a best-practice?
I know it cannot hurt to do it, but sometimes there are a number of class variable (references to indivudual UI elements etc), so I'd really like to know for my own understanding, what's really going on.
Thanks in advance!
You had it right when you said that the garbage collector will pick up references that are isolated. Specifically, any graph of references not connected to the execution thread will be collected. Because of this, there is no good reason to set your variables to null that I can see. Any advantages would be far outweighed by the code maintenance cost.