Why is this a memory leak - android

I came across a library for memory leak detection in Android (Java) called LeakCanary but cannot understand the example where they leak the memory. Could anybody please explain how and why the code shown in their example is a memory leak.
class Cat {
}
class Box {
Cat hiddenCat;
}
class Docker {
static Box container;
}
// ...
Box box = new Box();
Cat schrodingerCat = new Cat();
box.hiddenCat = schrodingerCat;
Docker.container = box;
and then they watch the variable schrodingerCat for leaks which gives a leak shown as follows (which I dont know how to relate to the above code).
* GC ROOT static Docker.container
* references Box.hiddenCat
* leaks Cat instance
Any help with the explanation of the leak and how the detection relates to it would be very helpful. Also some good articles for beginners would be nice.
Thanks!

First, let's understand what is a Memory Leak:
Definition
Memory Leak is data allocated (bitmaps, objects, arrays, etc) in the RAM that the garbage collector (GC) is unable to free, although it is not needed anymore by the program.
Example
A user is opening a view that shows an Image. We load the bitmap to the memory. Now the user exit the view and the image is not needed anymore and there is no reference to it from the code. At that moment the GC comes into action and remove it from the memory. BUT, if we still had a reference to it, the GC will not know it is OK for removal and it would have stayed in the RAM taking unneeded space - aka Memory Leak.
Cat in A Box
Let's say we have a Cat object in our app, and we hold it in a Box object. If we hold the box (have a reference to the Box object) and the Box holds the Cat, the GC will not be able to clean the Cat object from the memory.
The Docker is a class that has a Static reference to our Box. This means that unless we nullify it, or re-assign the value, the Docker will keep referencing the Box. Preventing the Box (and the inner Cat) from ever being removed from the memory by the GC.
So, do we need the Cat? is it still relevant for the App?
This is up to the developer to decide how long we need the Cat for. LeakCanary and other diagnostic tools suggest of a possible Memory Leak. They THINK that the object (Cat) might not be needed anymore so they alert that it is a leak.
Recap
In the example, they give a common scenario of a Memory leak. When using a Static reference we prevent from the GC to clean an Object. You should read this:
* GC ROOT static Docker.container
* references Box.hiddenCat
* leaks Cat instance
as:
Object Cat might be not used anymore but was not removed from memory by the GC.
The reason the object Cat was not removed is since Box is having a reference to it.
The Reason the object Box was not removed is since the Docker has a static reference to it.
Static reference by Docker is the ROOT of the tree that causes the possible leak.

It looks like the RefWatcher instance used to "watch the variable schrodingerCat for leaks":
refWatcher.watch(schrodingerCat);
forces a set of GC passes and if the reference passed in isn't collected during those GC passes it's considered a leak.
Since the static Docker.container.hiddenCat is keeping a GC rooted reference to the object originally known as schrodingerCat, it can't be GC'ed so when you ask RefWatcher to check it. Therefore it lets you know that the object can't be collected.

I suggest you read this answer https://stackoverflow.com/a/11908685/1065810
It will probably help you understand the example above.
In brief, in your example, the class Docker keeps a reference to a Box. Even when the container box is not needed anymore, the class Docker still holds a reference to it thus creating a memory leak.
Let me know if that helps.

Related

Understanding Garbage Collection in android

I Think i Need Some Help to Understand Garbage Collections, well i know garbage collection clears those who have no referrence from a live Thread, so for example i have a class that Decodes images like this:
new ImageDecoder(MyImageView).Decode();
do i need to keep a reference to the ImageDecoder class and null it later, or it will recycle whenever i call MyImageView.setBackgroundResource(0); ?
or whenever that i create a reference to a class and that Class adds tons of stacks, so whenever i do
MyClass aClass;
...
aClass = null;
Then the Heap Should be Freed From all Heap that Class Took according to the Articles, But It doesnt Happen in real life as i see , how is that working?
thanks alot;
You cant controll in Java and same applies here. Assigning aClass = null doesnt mean GC will run immediately and free memory on heap. It will run when he thinks JVM is running out of memory and creation of new objects require more space then it may run which in case my stop your main thread and freeze your app.
Oracle Java GC Basics

Understanding Android App RAM Usage

My app uses a service which I start in the main activity's onCreate() method. When I first launch the app on my tablet, and view what's running in Settings/Apps/Running, it shows my service running and consuming 11MB of RAM.
Now, if I cycle the activity's life cycle 20 times by rotating the device, and go back into Settings/Apps/Running, it shows that I'm now using 29MB of RAM.
At first I thought this must be due to a memory leaks, but after taking heap dumps before and after cycling the activity's life cycle, I don't appear to be leaking any objects. Below is a screenshot from MAT, where the column titled Objects #0 lists instances of my objects before cycling, and column titled Objects #1 lists instances of my objects after cycling.
and for all objects
There don't appear to be any obvious memory leaks, and yet I can't understand why the RAM usage in Settings/Apps/Running increases after each orientation/lifecycle. Am I missing something here? Why is my RAM usage apparently increasing, when I don't appear to have any memory leaks?
Update
The reason my app was consuming more RAM on each orientation change was the result of creating custom fonts from assets. I had created a custom TypefacedTextView (can be seen as an object in the screenshots above) that appears to have been reloading the fonts into memory each time the view was created. Removing the TypefacedTextViews has fixed the problem. The problem was made clearly apparent using the adb tool with command shell dumpsys meminfo my.package.com which listed my abundant font Asset Allocations.
There's a short blog post which, I believe, holds a lot of information nonetheless. You can find it here.
In it you find an intereseting explanation of what can/will happen if you manage your Activity's references wrongly:
private static Drawable sBackground;
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
This code is very fast and also very wrong; it leaks the first
activity created upon the first screen orientation change. When a
Drawable is attached to a view, the view is set as a callback on the
drawable. In the code snippet above, this means the drawable has a
reference to the TextView which itself has a reference to the activity
(the Context) which in turns has references to pretty much anything
(depending on your code.)
Since you're talking about memory leaks on orientation changes, you may very well be making the mistakes the author details in his post.

what different between WeakReference and SoftReference

I find the document on this link
It describe as below:
Weak references are useful for mappings that should have their entries removed automatically once they are not referenced any more (from outside). The difference between a SoftReference and a WeakReference is the point of time at which the decision is made to clear and enqueue the reference:
A SoftReference should be cleared and enqueued as late as possible, that is, in case the VM is in danger of running out of memory.
A WeakReference may be cleared and enqueued as soon as is known to be weakly-referenced.
But when I look through the Dalvikvm's source code, found something in dvmCollectGarbageInternal(Heap.cpp L446 Android 4.4) function. It seem two references are
cleared at the same time.
/*
* All strongly-reachable objects have now been marked. Process
* weakly-reachable objects discovered while tracing.
*/
dvmHeapProcessReferences(&gcHeap->softReferences,
spec->doPreserve == false,
&gcHeap->weakReferences,
&gcHeap->finalizerReferences,
&gcHeap->phantomReferences);
Do I miss something?
================================================================================
With #fadden's help, I found the reserve code
if (!marked && ((++counter) & 1))
The dalvikvm reserve the half sofereference every GC procedure, and I copy someone's test code the test
final ArrayList> list = new ArrayList>(
SR_COUNT);
for (int i = 0; i < SR_COUNT; ++i) {
list.add(new SoftReference(new Integer(i)));
}
/* Test */
for (int i = 0; i < 3; ++i) {
System.gc();
try {
Thread.sleep(200);
} catch (final InterruptedException e) {
}
}
/* Check */
int dead = 0;
for (final SoftReference<Integer> ref : list) {
if (ref.get() == null) {
++dead;
}
Log.d(TAG, "dead: " + dead);
}
All the log from logcat is just what I think.
FWIW, the best description of weak/soft/phantom references in Java is in chapter 17 of The Java Programming Language ("Garbage Collection and Memory").
There's no mandated policy for soft reference retention. The VM is allowed to discard all or none during a GC, or anything in between. The only requirement is that the VM is supposed to discard all softly-reachable objects before throwing OOM.
You can continue Dalvik's logic in dvmHeapProcessReferences() in MarkSweep.cpp. Note in particular the call to preserveSomeSoftReferences(), which retains some but not others based on the reference "color". You can read more about colors on the wikipedia GC article.
From Understanding Weak References, by Ethan Nicholas:
https://weblogs.java.net/blog/enicholas/archive/2006/05/understanding_w.html
Weak references
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. You create a weak reference like this:
WeakReference weakWidget = new WeakReference(widget);
and then elsewhere in the code you can use weakWidget.get() to get the actual Widget object. Of course the weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the widget) that weakWidget.get() suddenly starts returning null.
...
Soft references
A soft reference is exactly like a weak reference, except that it is less eager to throw away the object to which it refers. An object which is only weakly reachable (the strongest references to it are WeakReferences) will be discarded at the next garbage collection cycle, but an object which is softly reachable will generally stick around for a while.
SoftReferences aren't required to behave any differently than WeakReferences, but in practice softly reachable objects are generally retained as long as memory is in plentiful supply. This makes them an excellent foundation for a cache, such as the image cache described above, since you can let the garbage collector worry about both how reachable the objects are (a strongly reachable object will never be removed from the cache) and how badly it needs the memory they are consuming.
And Peter Kessler added in the comments:
The Sun JRE does treat SoftReferences differently from WeakReferences. We attempt to hold on to object referenced by a SoftReference if there isn't pressure on the available memory. One detail: the policy for the "-client" and "-server" JRE's are different: the -client JRE tries to keep your footprint small by preferring to clear SoftReferences rather than expand the heap, whereas the -server JRE tries to keep your performance high by preferring to expand the heap (if possible) rather than clear SoftReferences. One size does not fit all.

Logic behind memory leak in android

Normally in c++ what memory leak is , If we have alloted an object like
Obj c = new Obj();
then if we do
c = b; (example)
we lose the pointer to the object c that's the memory leak.
Question:
But in android Garbage collector collects object when there is no pointers pointing to them. So why there is memory leak even after that ?
Update
All the answers points to holding reference to unused objects is causing memory leak. Thats right. But is that the only cause of memory leak. Holding pointers will be released when activity is finished unless it is static. There are bitmaps and other memory hunger objects , don't they cause any problems in this
In Android/Java memory leak occurs
when you are keeping the reference of an object/instance even after it is no longer required.
when you keep open a file stream, when you are done with it.
Unclosed connections
There are other reasons for memory leak as well, but these are the most common ones.
In garbage collected runtimes, a memory leak means that an object cannot be collected even if it is no longer used. For example, a reference is held to an object but the reference is no longer used for anything.
Casually, the term memory leak is used to refer to situations where these incollectible objects keep on accumulating, increasing the allocated heap size and eventually leading to OOM.
There might be a leak when a Context (an Activity, Service, etc.) is retained by any helper class that would have a reference to it.
Illustration: instead of this:
public class Helper {
private static Context mContext;
public Helper(Context context){
mContext = context;
}
public static void methodDoesSomething(){
...
}
}
Use the context without retaining it by passing it as a parameter:
public class Helper {
public static void methodDoesSomething(Context context){
...
}
}
Because Android will want at some point to destroy an Activity for instance, and an object has a reference to it, The Garbage collector can not remove that Activity thus we have a memory leak.
The answer is partially in your question: Precisely because those references are not freed. Suppose a situation where you have an instance of a class, you've ended working in it but for certain circumstances, the instance keeps there in a state it's not freed. Additionally to Garbage Collector unability to free it, if not controlled, the amount of memory may even increase if it's not handled.
There is one additional thing too. You may have a code that looks correct and well written, but when you instantiate some native libraries, that means you're referencing an hierarchy of classes. If you're not aware of what are you doing, you may precisely handle incorrectly some references and lead to memory leaks. One very popular example is keeping a Context reference into your class. The context instance is never freed and a reason of huge memory leaks.
There are solutions for this, additionally to the obvious (free objects when you're done, etc.). In Java there are SoftReferences, WeakReferences, and other. This objects are containers that tell the Garbage Collector that they have preference on being freed once unused or there are no other references pointing to them. So you're helping the GC to know what should be freed. They're dangerous at a certain point in Android environments, as apps are limited too 16MB of heap, so a WeakReference might be collected too fast. It's necessary to check whether the object still exists.
I think we need to define "Memory Leak" in the first place. Memory leak is something you don't need anymore but it still in the memory and each time a new object is created, a new place will be allocated in the memory. The application will hold more and more memory in time.
private static Drawable background;
#Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this);
background = getDrawable(R.drawable.large_bitmap);
label.setBackgroundDrawable(background);
setContentView(label);
}
Above example, TextView get Activity as reference, which is a link between
TextView and Activity
now, then there is a static variable
background
which holds the background drawable, static variable will be alive until the application is destroyed or finished. Imagine that you want to destroy the activity, when you destroy static variable will still hold a link to activity, because of that garbage collector won't be able to collect it.
You can have a look at here about more.

DDMS Heap - 1-byte array(byte[], boolean[])

I experience some memory leaks in my android application. I've already used MAT to analyze the memory usage. But I have one question from the DDMS perspectiv in Eclipse, what does 1-byte array[byte[], boolean[]) mean?
Is this specific for my application? You can see that this is the big memory leak issue, this always increases in size, and the rest will increase and decrease randomly. My guess is that the GC doesn't catch this type. Can anybody explain why this happen, with this little information?
One byte array is the designation for any data structure that is organized as a single byte array. In you case and with that size, I would bet in a Bitmap or a Drawble.
Most common reasons for memory leaks are static object not properly managed and holding references to:
Context
View (which holds reference to context (and possibly also to bitmap)
Thread (which are not easly collected by GC)
Handler (which holds reference to context)
Most of them can be solved ensuring that you set the object to null when it's no long required.
Regards.
A byte and a boolean are each 1 byte. If you have an array of those you have a "1-byte array".
A ByteBuffer for example should internally hold one of those.
You have a total of 614 of them where the smallest one be a byte[24] (or boolean[24]), the largest one is 3MB. All of them together use 104MB.
The GC will get rid of them if they are no longer referenced.
For example when you put
private static byte myArray[] = new byte[3 * 1024 * 1024];
in one of your classes and never set it back to null (myArray = null) then this one can't be garbage collected because another Object has a reference to it. The object would be the class itself (as in String.class). The class object can't be garbage collected since classes are never unloaded. (they are referenced by their ClassLoader which could itself be referenced / loaded by another ClassLoader and you can't create Objects & use classes without them - they need to stay and they need to keep a reference to their classes)
It's usually not that simple but often start with static somewhere.
Within MAT (after you force GC) look at the reference chain for the objects that are no longer intended to stay alive and identify the one Object that holds the reference. Set that one to null in your code and your leak is gone. Explained in more detail here:
http://android-developers.blogspot.de/2011/03/memory-analysis-for-android.html
I ran to this problem tonight and almost I checked every bit of code but I couldn't find anything.
What I did was starting the app from intelij and then pressing home button and open the app again. Every time the app heap was doubled.
Finally I discover when I launch the app from ADB and press the home button and open the app again it doesn't bring back the old activity, it just start a new one. When I pressed finish it starts to cycle through all of them. It's like they are treated as two different intent. So I put android:launchMode="singleTop" on the main activity in manifest and it resolved the problem.
Although it's not the main cause of this problem but if you encountered this check this out before anything. It wasted three or four hours for me.

Categories

Resources