I am constantly struggling with identifying memory leaks. I guess I have several memory leaks in my project circular progress view.
One of my guesses is I have a memory leak in the internal class FadeRunnable.
But to be honest I don't know exactly how to find out if this is exactly the source of the problem. Well, when I do the usual scenario and switch the orientation I see an increase of the memory usage as shown below. And if I comment out the usage of the FadeRunnable class the steps are smaller (but still there, so I guess that's not the only leak)
Once I analyze the heap dump, I see something. But actually I don't know what the values mean. The things I do is
Change orientation many times
Open heap dump and sort by 'Retained Size'
Now when I click on "CircularProgressView' I see 8 rows in the right area. I guess this means there are 8 instances of the 'CircularProgressView' leaked and living somewhere as orphan in the memory.
Is this correct? If so, how can I find out in the dump information (I guess somewhere in the lower pane) where this object is saved/held.
I would love to have a step-by-step explanation how to find out if and which object is leaking some memory.
All of the code of the suspected view can be found in this class.
https://github.com/momentummodules/CircularProgressView/blob/master/circularprogressview/src/main/java/momentum/circularprogressview/CircularProgressView.java
But also feel free to check out the full project for deeper insight and if you want to play around with it.
Thanks in advance!
UPDATE
The code link from above shows the fixed code of the mem-leaking inner class. The following snippet shows the original mem-leaking code that should never be used like that
/**
* Mem-leaking code, for fixed code see repository link
* https://github.com/momentummodules/CircularProgressView/blob/master/circularprogressview/src/main/java/momentum/circularprogressview/CircularProgressView.java
*/
public class CircularProgressView extends View
{
...
private Thread fadeThread = null;
...
...
class FadeRunnable implements Runnable
{
#Override
public void run()
{
...
}
}
...
...
private void startFade(boolean fadeIn)
{
// check existing
if(this.fadeThread != null)
{
// check if fade is already running
switch(this.fadeThread.getState())
{
case TERMINATED:
case NEW:
this.fadeThread = null;
break;
case RUNNABLE:
case BLOCKED:
case TIMED_WAITING:
case WAITING:
return;
}
}
// create new
this.fadeThread = new Thread(new FadeRunnable(fadeIn, this.fadeTime));
this.fadeThread.start();
}
}
Yes, you do have a memory leak in FadeRunnable class.
Every instance of inner class contains implicit reference to its outer class, accessible through OuterClass.this operator. In your project, when you execute the FadeRunnable and then trigger reconfiguration by orientation change, the whole activity and your CircularProgressView contained within get recreated, but the FadeRunnable from previous is still alive (allocated) and, because of it holding implicit reference to its outer CircularProgressView class, the view continues to live also, that's why after several reconfigurations you have 8 instances of CircularProgressView allocated in memory, and that gets worse - every View keeps a reference to it's context, and this cannot be freed also, resulting in bad memory leaks.
Runnables, Handlers and similar objects that can out-live their enclosing activities, fragments, views etc. should be declared as standard classes or STATIC inner classes (a static inner class doesn't hold implicit reference to its outer class), and shouldn't keep references such as Context, View etc., instead you can keep a WeakReference<> so when your Activity is recreated through config change, the View can be destroyed and freed by garbage collector.
This is a very informative article on the subject, I strongly suggest reading it.
I guess you have the correct direction there. This FadeRunnable is certainly not cool. Even if you have other memory leaks, you defo should check this out.
In general what you should really be doing in a view is quite different, specially that views already have facilities to deal with timing and animation without the need for threads.
I'll suggest you what I believe is a simpler and cleaner approach to animate stuff on views.
Start by removing your runnable and thread completely.
then to start an animation you do:
ValueAnimator animation = ValueAnimator.ofFloat(0, 1);
animation.setDuration(500);
animation.addUpdateListener(animationUpdate);
animation.addListener(animationUpdate);
animation.start();
and then you need those listeners
// this gets called for every animation update,
// inside this call you update `CircularProgressView.this.fadeAlpha`
private final ValueAnimator.AnimatorUpdateListener animationUpdate = new ValueAnimator.AnimatorUpdateListener() {
#Override public void onAnimationUpdate(ValueAnimator animation) {
// this fraction varies between 0f and 1f
float fraction = animation.getAnimatedFraction();
// ... do your calculation
ViewCompat.postInvalidateOnAnimation(CircularProgressView.this);
}
};
// this is an optional one only if you really need
// in that you get notified when the animation starts and ends
private final Animator.AnimatorListener animationListener = new AnimatorListenerAdapter() {
#Override public void onAnimationStart(Animator animation) {
// anything u need goes here
ViewCompat.postInvalidateOnAnimation(CircularProgressView.this);
}
#Override public void onAnimationEnd(Animator animation) {
// anything u need goes here
ViewCompat.postInvalidateOnAnimation(CircularProgressView.this);
}
};
and that's about it.
On the topic of actual memory leak analysis I'll suggest you to from now on and forever use the leak canary library: https://github.com/square/leakcanary it's a great tool to help us (developers) track memory leaks.
edit:
Why are you having a memory leak on this animation?
It's quite simple:
on startFade(boolean); you create a new thread and a new runnable
the runnable have a reference to the view (because it's an non-static inner class)
the thread have a reference to the Runnable, so can run it.
the framework destroy the view, because it's not part of the UI anymore (rotation, back button)
the thread is still running, with the runnable still looping, with the View object still not destroyed because the Runnable references it.
the view Object have an instance of Context, and this context is the Activity.
So at the end of this sequence your activity will not be garbage collected by the GC, AKA: Memory Leak !
Related
Here is my very simple code :
class UpdateAlertActivity extends Activity {
O o ;
WeakReference<O> _o ;
ArrayList<O> arr = new ArrayList<>();
static class O {
private String l ;
public O(String l) {
this.l = l ;
}
}
void test()
{
arr.clear();
Runtime.getRuntime().gc();
Log.i(LOG_TAG, "breakpoint");
}
#Override
protected void onResume()
{
super.onResume();
o = new O("hello");
arr.add(o);
_o = new WeakReference<>(o);
test();
}
}
As I clear array in test() method, I was excepting _o.get() to be null at my breakpoint, but it's not the case. When I see in the debbuger where o is held, it shows me only in the weak reference _o, while I thought weak reference are made to free their instance when there is no other strong reference on them...
I saw on StackOverflow that I missed calling GC, but calling it had no effect in my program as you can see.
EDIT :
Even this super simple code does not work as excpected, it makes no sense...
O o = new O("lol");
WeakReference<O> _o = new WeakReference<>(o);
Log.i(LOG_TAG, "1:" + _o.get().toString());
o = null ;
Log.i(LOG_TAG, "2:" + _o.get().toString());
System.gc();
Log.i(LOG_TAG, "3:" + _o.get().toString()); // output not null here
EDIT2 :
I wanted the use of GC because I have, in another static class, an array called lastUpdates, which is filled with app updates sent by my server wia TCP, sometimes.
All my activities observes this lastUpdate array (by implementing Observer/Observable interface), and when it is changed, all are notified, and call a particular function onUpdate(ArrayList u) with the list of new arrived updates as a parameter. This function process the updates only if the activity is resumed (changing UI during activity sleep causes app to crash).
If the entiere app is "sleeping" (user is in device menu for example), I want only the first activity waking up to be able to process new updates.
For that, I created in my activity class a array pendingPersistentUpdates storing weak references of all updates that has been catch when activity was sleeping. When the first activity wakes up, the updates catch during app sleep time are still in lastUpdates array, so I expect the weak references stored in pendingPersistentUpdates activity prop to return the actual updates, so my activity can UI-process them, at onResume.
I was expecting this situation :
An activity A run, an activity B is paused (behind activity A for example)
App receives an update U. All activities (A and B) are notified. A process the update because it's running, as expected. B store this update in its pendingPersistentUpdates, because it's paused.
A pause, user returns to B. At A pause, lastUpdates array is cleared, so the weak references of the updates in B pendingPersistentUpdates would return null
B resume, but pendingPersistentUpdates weak references are null (lastUpdates has been cleared), so U is not processed.
Though, as lastUpdate.clear() does not fire GC, B pendingPersistentUpdates updates still exist, and are processed a second time (behavior not desired)
It is not possible to force the garbage collector to run. Runtime.getRuntime().gc() is just an alias for System.gc(), and both are just a hint (read the docs; they mention this). In particular, calling gc() usually means the collection will occur in some other thread; so it's more the 'start sign' for the collector; gc() doesn't necessarily pause and wait around for the gc to finish a full cycle, it merely tells the gc to start one. Whilst, again, no guarantee, Thread.sleep(10000L); makes it more likely you'll see the effects of the GC call.
A WeakReference merely guarantees that the existence of this object won't impede on any garbage collection of the object it refers to. That's all. It doesn't instantaneously lose its referent when the only way to get to the referent is via WeakReference objects. That'll happen later (in fact, that will happen before the object is GCed: First the collector will wipe out all weakrefs, and sometime later will the memory that the object occupied be truly free for use). So, what you're observing in your debugger (that the only way to get to the object is via that WR) isn't inherently broken.
Note also that the debugger itself can be the issue. Merely being there and observing it can have an effect (so make sure you run it without as well).
If you want the GC to try harder, you can allocate some fairly large arrays and pause the thread, that can help, but there is nothing you can do to guarantee a GC run. If you want to observe, run java with java -verbose:gc restOfArgsHere, and keep an eye on the console; if a GC actually occurs, you'll see it.
However.
Your code as pasted doesn't even compile which suggests you either pasted only half of it, or you edited it some 'for clarity' (often a bad idea, best to paste precisely what you're working with!). In particular, you write o = new O("hello");, but o isn't defined anywhere. If it is a field of your class, it would imply the referent cannot be collected at all! So you might want to check on that. Make that O o = new O("hello"); instead of what you have. Assuming you read your debugger correctly and it's functioning properly, this isn't it, but it is suspicious.
Calling the garbage collector only suggests to the system that it should free up memory, it does not force it explicitly. This means that the collection may not actually happen if there is enough memory.
https://developer.android.com/reference/java/lang/System#gc()
Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.
Notice the next sentence "the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects"
Internally the garbage collector uses heuristics / thresholds to decide when to collect unused objects, so, basically when the JVM needs memory.
In this case I am trying to understand some concepts related to memory leaks in Android. Though it is a frequent question, I am more interested on a real justification rather than a simple answer like "do not keep a reference to the activity".
These are the pages I've been reading so far:
link1: Garbage-Collection Roots—The Source of All Object Trees
link2: Memory leaks in Android
link3: Memory leaks in Android
and my conclusion so far is that the only way to have memory leaks with activities is when a component has a reference to an Activity and the lifecycle of this component is beyond the activity's lifecycle. The time you have a memory leak depends on the lifecycle of that component.
With that being said, I found this discussion with Jake Wharton related to Dagger 2 in an MVP architecture, where he wrote:
There is no leak. If the activity has outgoing references to
dependencies and there are no incoming references to the activity it
will be garbage collected.
As far as I know, if I have an activity which has a reference to a presenter which has a reference to a view interface (the implementation is the same activity), and then the activity is being recreated with a new presenter, then I do not see the reason why we can have memory leaks: the old activity and presenter are not longer reachable and thus they are potentially garbage collected. The only way I can have memory leak is if the presenter or any component inside the presenter has a lifecycle beyond the activity's lifecycle.
My questions are:
Am I missing something here?
Does having a reference to an activity mean I will have memory leaks? If that so, then does it mean the activity is considered a Garbage-Collection Root
It took me time to get back to this question and get all the information possible to understand how this works and see if the statement "if you have an object referring to an Activity which has been replaced by another activity, then you have a memory leak" is true.
Firstly, I decided to run some code to see the memory's behaviour. I used a simple MVP project I have.
The first thing I have done is to keep a reference to the activity in my presenter after the onDestroy method has been called:
public abstract class BasePresenter<T> {
//Activity or Fragment attached to Presenter
protected T view;
public void onViewCreated(T view) {
this.view = view;
}
public void onStart() {
}
public void onResume() {
}
public void onPause() {
}
public void onStop(){
}
public void onDestroyed() {
// view = null;
}
}
Then I turned on the "do not keep activities in memory" option and recreated the activity a couple of times.
When I dumped the memory I saw multiple instances of that activity, but after calling the garbage collector with the android memory profiler option they disappeared (as you know the GC is not called every time due to performance issues, just when it is needed).
So in this case the statement "if you have an object referring to an Activity which has been replaced by another activity, then you have a memory leak" is not true, or at least it is not complete to be true. In order to get a memory leak, that dependency graph needs to be referenced by a GC root.
Then I decided to uncomment that line in onDestroy:
public void onDestroyed() {
view = null;
}
and have a static reference to a view in my fragment (views have a reference to the activity where they are created)
private static View viewLeak;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
progressBar = view.findViewById(R.id.progress);
if(viewLeak == null){
viewLeak = progressBar;
}
}
Again, I repeated the process of recreating the activity and in this case I had multiples instances of the same activity (two instances: one which was actively used and another one referenced by the static view). Of course I called the garbage collector but that extra instance of the activity stayed in memory. What changed here is that in this case we have a GC root which is the static variable:
Static variables are referenced by their classes. This fact makes them de facto GC roots. Source
Of course, there are multiple cases where you can get a CG root and thus, multiple cases where you can get memory leaks.
I hope this helps you to clarify some concepts related to memory leaks in Java as it did to me.
Other sources that were useful to understand this are:
LINK1, LINK2, LINK3
NEW CONTENT:
This is a video from google I/O talking about memory leaks. Please, pay attention when he says "long-live objects having a reference to an Activity" - minute 25:30.
Suppose you have an object A that has a reference to Activity B. Now suppose you finish the Activity B. You can be sure that B is ready to be garbage-collected.
Now suppose you manually call the GC. Will it recycle the Activity B? No! Why? Because there's one object referring to it (object A).
This is how a memory leak is born.
I have a question concerning the thread:
In my activity I get a list of threads(more exactly a list of Runnable). Inside these threads, I check if the time written in the activity is the same as the current time (basically like an alarm).
When I press back on my android, my activity finishes and I go back to the main screen of my phone...however the thread are still there (which makes sense for me as it is initialized in the heap).
However when I return to my app, I have no way to get access back to these threads...
DO you have an idea how to do it?
Here is a part of my code:
public class SmartAlarm extends AppCompatActivity {
private List<Runnable> listThreadAlarms;
#Override
protected void onCreate(Bundle savedInstanceState)
{
listThreadAlarms = new ArrayList<>();
for(Alarm alarm: alarmList) {
Runnable activateAlarm = new ActivateAlarm(this,(int)alarm.getId()-1,"alarm"+(alarm.getSound()+1),alarm.getTitle());
Thread threadAlarm = new Thread(activateAlarm);
listThreadAlarms.add(activateAlarm);
threadAlarm.start();
}
}
}
i think you should rethink your design. more on this to follow...
I Do NOT Recommend This
if you MUST retain references to these objects, one way to do this is to stash them as instances in a static collection in a long-lived singleton. a custom android.app.Application instance would be an option since it lives for as long as your app does and you can reference it from any standard component such as an Activity, ie:
public class MyApplication extends Application {
public static List<Runnable> runnables;
}
add Runnable instances to the collection as they are created...
...however, i have no idea what the criteria would be for removing them. Runnables are meant to run to completion/error, and then be GC'd. since they don't return a result, we'd need some sort of state within the Runnable instance to know if it has completed its work, which means it can then be removed from the collection so as to be GC'd. by keeping them in this collection, they live beyond their scope of viability, and we've created extra housekeeping for ourselves in pruning the collection.
this sort of approach would technically work, but strikes me very odd and untestable.
I DO Recommend This
let the Runnables communicate the state of their tasks independently through another medium, ie:
shared preferences
a database
an in-memory collection stored in the Application
when your SmartAlarm instance starts, interrogate the state of the associated tasks through that medium.
This question has been edited to provide as much information about the problem as possible, as someone suggested I should do. Now that there’s bounty on it—that only seems like the right thing to do. Good luck, people!
Don’t forget you can always ask additional questions if you feel there’s something I didn’t include!
Introduction
I’m working on a system for procedurally generating terrain as a character walks around using various different noises—mostly perlin- and simplex-noise. The world itself has three dimensions, althought it’s viewed as top-down in two dimensions inside the game.
For those of you used to procedurally generating terrain, you’ll be aware of the fact that it’s necessary to use multithreading in order for it not to cause lag spikes within the renderer thread. That’s exactly what I’ve been trying to do, with a little help from LibGDX’s AsyncExecutor, as well as the same library’s AsyncTask, which is a task running on the thread offered by the AsyncExecutor.
Problem
My problem is that the AsyncExecutor doesn’t seem asynchronous at all. It causes lag spikes within my renderer thread, which in theory could be from it using a resource that also is used by the renderer thread. The thing is, however, that the renderer thread generates in new “chunks”—I call them regions—that the AsyncExecutor then work on. The renderer thread isn’t allowed to render that resource until it has been fully generated by the AsyncExecutor.
RegionHandler
I have a class called RegionHandler which places new regions in the direction the player is moving and removes regions from the opposite directions—in order for the program not having to be aware of more than 13 x 9 regions at one time.
Here’s a brief piece of code explaining how it works—the comments are there to simplify discussing different pieces of the code:
// These ‘if’s are triggered when the player moves
// to a certain position
if(addLeft)
{
// Adds new regions to the left and removes to the right
// ...
// Submit ‘RegionLoader’ task to ‘asyncExecutor’
// with regions that needs be generated as well as ‘toSends’ which is
// also part of that generation
asyncExecutor.submit(new RegionLoader(toGenRegions, toSends));
}
else if(addRight)
{
// Adds new regions to the right and removes to the left
// ...
// Same as previous ‘submit’ to the ‘asyncExecutor’
asyncExecutor.submit(new RegionLoader(toGenRegions, toSends));
}
if(addBottom)
{
// Adds new regions to the bottom and removes to the top
// ...
// Same as previous ‘submit’ to the ‘asyncExecutor’
asyncExecutor.submit(new RegionLoader(toSend, toSends));
}
else if(addTop)
{
// Adds new regions to the top and removes from the bottom
// ...
// Same as previous ‘submit’ to the ‘asyncExecutor’
asyncExecutor.submit(new RegionLoader(toSend, toSends));
}
The asyncExecutor is in fact and AsyncExecutor and the RegionLoader implements the AsyncTask interface. I’ve tested to see how long this piece of code takes to run through—this piece of code never takes over a single millisecond to run through.
The Regions are handled inside a list:
List<List<Region>> regions;
RegionLoader
This class is a task with the capability of being run by an AsyncExecutor.
private class RegionLoader implements AsyncTask<Object>
{
private List<Region> regions;
private List<ToSendInner> toSends;
public RegionLoader(
List<Region> regions,
List<ToSendInner> toSends)
{
this.regions = regions;
this.toSends = toSends;
}
#Override
public Object call() throws Exception
{
// Generates the ‘Region’s it has been given inside the constructor
// ...
return null;
}
}
Once call() has finished it’ll set a boolean to true that allows for the rendering of that specific Region.
Furthermore
Although the AsyncExecutor is meant to be asynchronous, it causes lag spikes every once in a while inside the renderer thread. As mentioned earlier, this could be caused by the AsyncExecutor using the same resources as the renderer thread, but the renderer thread merely renders the Regions when it’s allowed to—for that reason I can’t see why that’d be what’s causing the lag spikes.
What I’ve tried so far
I’ve tried using regular Java threads, but I read somewhere that these might not work due to LibGDX supporting Android development and Android doesn’t have the same capabilities when it comes to multithreading—but I could truly be wrong!
Furthermore
Perhaps someone has experienced a similar problem over their game development careers? If so, maybe someone can point me in the right direction?
I'd take a look into the effects of your garbage collection, as you seem to be passing new Region objects to the tasks. Try reusing/repopulating existing Regions instead.
I don't remember any problems about Android and Threads and searched but didn't find anything. You should test it.
I will assume that generating regions is not anything related to openGL. So you don't have to run it on main thread.
Try this: Thread + Gdx.app.postRunnable()
new Thread(new Runnable() {
Variables...
public Runnable set(Variables... ) {
// set variables
return this;
}
#Override
public void run() {
// do stuff
Gdx.app.postRunnable(() -> {
// commit that stuff.
});
}
}.set(regions,whateverelse)).start();
If you look at the source code of AsyncExecutor you will see that it exactly does the same. But only it doesn't let a second runnable run at the same time.
https://github.com/libgdx/libgdx/blob/9b8f20b2d0e96e53f0f2b98dc8f6131c810aae71/gdx/src/com/badlogic/gdx/utils/async/AsyncExecutor.java
Note: The implementation of the AsyncExecutor is changed to instantly execution in the gwt backend. Because of the limitations I'd guess. You probably shouldn't target gwt.
Try it, and let me know. If main thread still hangs, it is because what you are doing in the //commit that stuff part. Post more of your code, there is not enough to understand the source of the problem.
EDIT : Also use Gdx.graphics.getDeltaTime() to see if there is really a hang. It might be caused by something else, so eliminate other possibilities and find out if the real reason is this task.
I'm working on an application where 90% of the activities inherit from a common activity and all these activities leak, meaning that if I go from A->B and then B->A (finish() is called), B's onDestroy() gets called but it still leaks (checked with MAT).
The leaked activities are quite big (10MB~) so after going back and forth a few times the app crashes with OOM.
I've checked the heap dump and followed the path to GC roots for the leaking activities and they all look like this:
So I guess it's something in the common superclass that's leaking. I've already checked that all the BroadcastReceivers and listeners are unregistered when the activities get destroyed and there are no Handlers used nor anonymous inner classes which may be causing the leak (it seems to me, at least).
What could be the cause of the leak? Any help would be really appreciated.
EDIT
I've found that there are two pieces of code that when commented out the activities are not leaking anymore:
Some lines of code that instantiate a ProgressDialog.
A call to postDelayed with an anonymous Runnable.
In the first case, the dialog's dismiss() function is called before destruction, so I don't know why this could be the problem. In the second case, removeCallbacks is called for the Runnable in onPause, so theoretically it's properly cleaned, isnt' it?
Cheers.
The problem turn out to be the anonymous Runnable in postDelayed. This Runnable was called with the postDelayed() function of the content view of the base activity, so it was something like this:
#Override
protected void onResume() {
...
mCallback = new Runnable() { ... };
getContentView().postDelayed(mCallback, mDelay);
}
The surprising part was that this callback was removed in onPause():
#Override
protected void onPause() {
...
getContentView().removeCallbacks(mCallback);
mCallback = null;
}
Why this didn't prevent the leak is still a mistery to me. At first I tried using getContentView().getHandler().removeCallbacksAndMessages(null) and it fixed the leak, but then the app had things completely broken apart in seemingly unrelated places.
In the end what fixed the leak was creating a Handler instance and calling postDelayed() and removeCallbacks() on this handler.