Is Memory Leak? Why Java.Lang.Ref.Finalizer Eat So Much Memory

is memory leak? why java.lang.ref.Finalizer eat so much memory

Some classes implement the Object.finalize() method. Objects which override this method need to called by a background thread call finalizer, and they can't be cleaned up until this happens. If these tasks are short and you don't discard many of these it all works well. However if you are creating lots of these objects and/or their finalizers take a long time, the queue of objects to be finalized builds up. It is possible for this queue to use up all the memory.

The solution is

  • don't use finalize()d objects if you can (if you are writing the class for the object)
  • make finalize very short (if you have to use it)
  • don't discard such objects every time (try to re-use them)

The last option is likely to be best for you as you are using an existing library.

Possible Memory leak through FinalizerReference

For more details about your issue, look at the referent field of your Finalizer.
Finalizer objects are just extended References, so you could investigate the content. It will give you information about the finalizing objects.

Depending on the content, you will have new leads. It is possible that the finalization process for the pending objects is very long. As you have only one thread processing them all, you may be somehow finalizing more than you can.

Cheers

Troubleshooting a java memory leak: finalization?

My first step would be to establish whether this is a genuine memory leak or not.

The points raised in the previous answers all relate to the speed at which objects are collected, not the question of whether your objects are collected at all. Only the latter is a genuine memory leak.

We had a similar predicament on my project, and ran the application in "slow motion" mode to figure out if we had a real leak. We were able to do this by slowing down the stream of input data.

If the problem disappears when you run in "slow motion" mode, then the problem is probably one of the ones suggested in the previous answers, i.e. the Finalizer thread can't process the finalizer queue fast enough.

If that is the problem, it sounds like you might need to do some non-trivial refactoring as described in the page Bringer128 linked to, e.g.

Now let's look at how to write classes that require postmortem cleanup so that their users do not encounter the problems previously outlined. The best way to do so is to split such classes into two -- one to hold the data that need postmortem cleanup, the other to hold everything else -- and define a finalizer only on the former

Unfinalized objects exhausting memory

This ultimately turned out to be caused by a JVM bug (unfortunately I've lost the link to the specific one we tracked it down to). Upgrading to a newer version of OpenJDK (we ended up with OpenJDK 1.7.0_50) solved the issue without us making any changes to our code.

Very strange OutOfMemoryError

I want to close this question with a summary of the current state.

The last test is now up over 60 hours without any problems. That leads us to the following summary/conclusions:

  • We have a high throughput server using lots of objects that in the end implement "finalize". These objects are mostly JNA memory handles and file streams. Building the Finalizers faster than GC and finalizer thread are able to clean up, this process fails after ~3 hours. This is a well known phenomenon (-> google).
  • We did some optimizations so the server got rid of nearly all the JNA Finalizers. This version was tested with jProfiler attached.
  • The server died some hours later than our initial attempt...
  • The profiler showed a huge amount of finalizers, this time caused mostly only by file streams. This queue was not cleaned up, even after pausing the server for some time.
  • Only after manually triggering "System.runFinalization()", the queue was emptied. Resuming the server started to refill...
  • This is still inexplicable. We now guess this is some profiler interaction with GC/finalization.
  • To debug what could be the reason for the inactive finalizer thread we detached the profiler and attached the debugger this time.
  • The system was running without noticeable defect... FinalizerThread and GC all "green".
  • We resumed the test (now for the first time again without any agents besides jConsole attached) and its up and fine now for over 60 hours. So apparently the initial JNA refactoring solved the issue, only the profiling session added some indeterminism (greetings from Heisenberg).

Other strategies for managing the finalizers are for example discussed in http://cleversoft.wordpress.com/2011/05/14/out-of-memory-exception-from-finalizer-object-overflow/ (besides the not overly clever "don't use finalizers"..).

Thank's for all your input.

Clueless About a (Possible) Android Memory Leak

It looks like the reason why the Remainder is growing is the growth of the number of Activity instances in the back stack (e.g. 13 instances of the "List" Activity + 13 instances of the "Main" Activity).

I've changed my Navigation Drawer so that when the user clicks the "Home" button (which takes him to the App's "Dashboard") I set the Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK flags: the Activity is re-used and the back stack is cleared (as recommended by the Android guidelines, actually). In fact, I should have done this already as I don't want several instances of the Dashboard ("Home") activity to be created.

By doing this I can see that the Activities are destroyed and allocated heap size (including the "Remaining" slice) decreases:

Fixing problem with increasing memory.

While fixing this, I also noticed that one of my Activities and a Bitmap used by it were not being destroyed, even if the back stack had been cleared (leak). After analysing with MAT I concluded that the source of this sub-problem was a reference to an ImageView that I kept in the Activity. By adding this code to the onStop() method, I've managed to get both the activity and Bitmap to be destroyed:

@Override
protected void onStop() {
super.onStop();

ImageView myImage = (ImageView) findViewById(R.id.myImage );
if(myImage .getDrawable() != null)
myImage.getDrawable().setCallback(null);

RoundedImageView roundImage = (RoundedImageView) findViewById(R.id.roundImage); // a custom View
if(roundImage.getDrawable() != null)
roundImage.getDrawable().setCallback(null);

}

I then generalized all my Activity and FragmentActivity so that they call unbindDrawables(View view) in onDestroy():

private void unbindDrawables(View view)
{
if (view.getBackground() != null)
{
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup && !(view instanceof AdapterView))
{
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
{
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}

Thanks to @NickT for pointing me in the right direction.



Related Topics



Leave a reply



Submit