Nazerke
Nazerke

Reputation: 2098

(AudioManager)getSystemService(Context.AUDIO_SERVICE) causing memory leak

I had memory leak that was being caused by AudioManager. So I've commented out this line in my code to see if it would solve my problem:

public class FireRoomActivity extends Activity {

AudioManager am;
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
  }
}

And it did solve the problem and I don't have memory leak any more. Is that because of Context.AUDIO_SERVICE? If yes then how could I replace it?

If it matters, I have this non-static class inside my activity that is not used elsewhere outside

class GestureListener extends GestureDetector.SimpleOnGestureListener {
RelativeLayout parentLayout;

public void setLayout(RelativeLayout layout){
    parentLayout = layout;  }
@Override
public boolean onDown(MotionEvent e) {
    return true;
}
// event when double tap occurs
@Override
public boolean onDoubleTap(MotionEvent e) {     
    makeArrowsVisible();
    parentLayout.findViewById(R.id.cabinet_zoomed).setVisibility(View.INVISIBLE);
    Button key = (Button)parentLayout.findViewById(R.id.key);
    if(key!=null){
        key.setVisibility(View.INVISIBLE);}
    return true;
}

Edit: screenshot of heap dump enter image description here

Upvotes: 3

Views: 9656

Answers (3)

Abhishek V
Abhishek V

Reputation: 12526

Fix mentioned in https://gist.github.com/jankovd/891d96f476f7a9ce24e2 worked for me.

public class ActivityUsingVideoView extends Activity {

  @Override protected void attachBaseContext(Context base) {
    super.attachBaseContext(AudioServiceActivityLeak.preventLeakOf(base));
  }
}


/**
 * Fixes a leak caused by AudioManager using an Activity context. 
 * Tracked at https://android-review.googlesource.com/#/c/140481/1 and
 * https://github.com/square/leakcanary/issues/205
 */
public class AudioServiceActivityLeak extends ContextWrapper {

  AudioServiceActivityLeak(Context base) {
    super(base);
  }

  public static ContextWrapper preventLeakOf(Context base) {
    return new AudioServiceActivityLeak(base);
  }

  @Override public Object getSystemService(String name) {
    if (Context.AUDIO_SERVICE.equals(name)) {
      return getApplicationContext().getSystemService(name);
    }
    return super.getSystemService(name);
  }
}

Thanks to Dejan Jankov :)

Upvotes: 2

JM Lord
JM Lord

Reputation: 1197

I found in another post that the AudioManager does keep a strong reference, but will still be properly garbage collected. See this google group conversation. Here's what I get out of it:

This means that if you manually launch a couple of garbage collections through the DDMS tab in Eclipse just before taking the head dump, this reference should not be there anymore.

This indeed solved the "problem" for me, as it turned out not to be a problem after all...

It was also mentionned that the debugger should not be on hook (i.e. use Run As... instead of Debug As...). The debugger being active could cause the references to be held by the AudioManager, thus creating a heap overflow (I have not tested this affirmation).

Upvotes: 1

Bracadabra
Bracadabra

Reputation: 3659

You can avoid memory leak using application context to get audio service.

Upvotes: 1

Related Questions