22

I'm experience some memory leaks in my application. The first time I suspected the memory leak was when I stress-tested my application by hitting a button to start a new Activity. After using DDMS and dumping out a .hprof file, this file I opened with the Eclipse Memory Analyzer

I got three possible Memory Leaks, shown in a Pie chart: enter image description here

And a description to the Memory Leaks:

Suspect 1

122 instances of "android.widget.LinearLayout", loaded by "" occupy 29 585 384 (38,74%) bytes.

Biggest instances:

•android.widget.LinearLayout @ 0x4258c008 - 2 268 848 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x425c8688 - 2 268 848 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x425e3988 - 2 268 848 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x4296e198 - 2 268 848 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x429d3aa8 - 2 268 848 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x42a10c78 - 2 268 848 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x448a1f10 - 2 268 848 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x44a65d58 - 2 268 848 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x42a14098 - 2 268 824 (2,97%) bytes. 
•android.widget.LinearLayout @ 0x4258bd30 - 999 528 (1,31%) bytes. 
•android.widget.LinearLayout @ 0x425c83b0 - 999 528 (1,31%) bytes. 
•android.widget.LinearLayout @ 0x425ddff8 - 999 528 (1,31%) bytes. 
•android.widget.LinearLayout @ 0x4296df80 - 999 528 (1,31%) bytes. 
•android.widget.LinearLayout @ 0x42a109a0 - 999 528 (1,31%) bytes. 
•android.widget.LinearLayout @ 0x42a13dc0 - 999 528 (1,31%) bytes. 
•android.widget.LinearLayout @ 0x448a1c38 - 999 528 (1,31%) bytes. 
•android.widget.LinearLayout @ 0x448cc338 - 999 528 (1,31%) bytes. 
•android.widget.LinearLayout @ 0x44a65a80 - 999 528 (1,31%) bytes. 

Suspect 2

15 instances of "android.widget.FrameLayout", loaded by "" occupy 29 405 016 (38,51%) bytes.

Biggest instances:

•android.widget.FrameLayout @ 0x4245b490 - 3 266 728 (4,28%) bytes. 
•android.widget.FrameLayout @ 0x4247a330 - 3 266 728 (4,28%) bytes. 
•android.widget.FrameLayout @ 0x425aa1d8 - 3 266 728 (4,28%) bytes. 
•android.widget.FrameLayout @ 0x425df8b0 - 3 266 728 (4,28%) bytes. 
•android.widget.FrameLayout @ 0x425efe68 - 3 266 728 (4,28%) bytes. 
•android.widget.FrameLayout @ 0x42627590 - 3 266 728 (4,28%) bytes. 
•android.widget.FrameLayout @ 0x42987a70 - 3 266 728 (4,28%) bytes. 
•android.widget.FrameLayout @ 0x4299df20 - 3 266 728 (4,28%) bytes. 
•android.widget.FrameLayout @ 0x448b6f28 - 3 266 728 (4,28%) bytes. 

Suspect 3

2 682 instances of "java.lang.Class", loaded by "<system class loader>" occupy 8 662 744 (11,34%) bytes. 

Biggest instances:

•class android.content.res.Resources @ 0x41a4f708 - 7 485 176 (9,80%) bytes. 

My first thought was to look in the R.java file, because I could see some hex references to the possible memory leak. I tried to search after the hex-string from Eclipse Memory Analyzer, but I couldn't find the addresses in the R.java file.

Then I looked in the Dominator Tree, and this is the result: enter image description here

This is only the first entry in the list, but this is the biggest one.

With this information, can anybody give me a hint on how I can track the Memory Leak? Add a comment if I need to add additional information to this post.

Thanks in advance.

EDIT

The problem may be in my Base class. All the Activities inherites from this class. This classes job is to set up a SlidingMenu, in the left upper corner. This is the code for this class:

 public class Base extends Activity implements OnSlideMenuItemClickListener {

        public SlideMenu slidemenu;
        ImageButton b;
        Time t; 

        BluetoothCommunicator btCom; 
        BroadcastReceiver btBroadCaster;
        MonitorBluetoothState bluetoothState;


        public void setTab(int id) {
            setContentView(id);
            overridePendingTransition(R.anim.activityfade, R.anim.activityfadeout);
            slidemenu = (SlideMenu) findViewById(R.id.slideMenu);
            slidemenu.init(this, R.menu.slide, this, 450);
            slidemenu.setHeaderImage(getResources().getDrawable(R.drawable.ic_launcher));


            b = (ImageButton) findViewById(R.id.BtnSlide);
            b.setOnClickListener(new OnClickListener() {

                public void onClick(View v) {
                    slidemenu.show();

                }   
            });

            b.setOnTouchListener(new OnTouchListener() {

                @Override
                public boolean onTouch(View v, MotionEvent event) {

                    switch (event.getAction()) {

                    case MotionEvent.ACTION_DOWN:
                        b.setImageResource(R.drawable.lincolor);
                        break;
                    case MotionEvent.ACTION_UP:
                        b.setImageResource(R.drawable.lin);
                        break;
                    }
                    return false;
                }
            });
        }

        @Override
        public void onSlideMenuItemClick(int itemId) {

            Class<?> cls = null; 

            switch(itemId) {
            case R.id.item_one:
                cls = Home.class;
                break;
            case R.id.item_two:
                cls = History.class;
                break;
            case R.id.item_three:
                cls = ClearHistoryDialog.class;
                break;
            case R.id.item_four:
                cls = SendLogDialog.class;
                break;
            case R.id.item_five:
                cls = PasswordDialog.class;
                break;
            case R.id.item_six:
                cls = About.class; 
                break;
            }
            Intent intent = new Intent(this, cls); 
            startActivity(intent); 
        }
    }

In my other Activities, this setTab method will be called like this:

    public class Main extends Base {
        public void onCreate(Bundle b) {
          super.onCreate(b);
          super.setTab(R.layout.Home);
        }
    }

Where the Home Layout is like this:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parent"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#e4e8ed"
    android:gravity="top" >

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/first"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="0px" >

        <include
            android:id="@+id/tabBar"
            layout="@layout/tab" />

        <com.workspace.tobias
            android:id="@+id/slideMenu"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <Button
            android:id="@+id/nist"
            android:layout_width="match_parent"
            android:layout_height="67dp"
            android:layout_gravity="center_horizontal"
            android:layout_marginBottom="3dp"
            android:layout_marginLeft="3dp"
            android:layout_marginRight="3dp"
            android:layout_marginTop="3dp"
            android:background="@drawable/ready"
            android:textColor="#FFFFFF" />

        <ListView
            android:id="@+id/lastCases"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />
    </LinearLayout>


    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="300dp"
        android:orientation="horizontal" >

        <ProgressBar
            android:id="@+id/progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:indeterminate="true" />

        <TextView
            android:id="@+id/loadingCases"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:text="@string/Loading"
            android:textColor="#707070"
            android:textSize="18dp"
            android:layout_marginLeft="10dp" />
    </LinearLayout>

</RelativeLayout>
Tobias Moe Thorstensen
  • 8,861
  • 16
  • 75
  • 143
  • 2
    The android resources you see there (suspect 3 / dominator tree) are not the problem - they exist in every app. The 30 MB frame / linear layouts could be a problem – zapl Nov 21 '12 at 09:56
  • 3
    Who is holding references to your layout, they shall have released those references. Chances are you keep a reference to a context, that is the main cause of memory leaks. Maybe an Activity or an inner class of an Activity is kept as a static field value ? – Snicolas Nov 21 '12 at 09:57
  • I think you need to post some more code. are you using fragments? just activities? handlers? – Ovidiu Latcu Nov 21 '12 at 10:38
  • 1
    addresses are in memory. R file references ids – njzk2 Nov 21 '12 at 10:38
  • you'll need topost more code from your Base and Home Activity. someone is retaining a context somewhere – njzk2 Nov 21 '12 at 10:39
  • 2
    @Tobias Moe Thorstensen. Try to get your hands on the object that holds references (ingoing references I believe in MAT ??) on your layouts objects. The problem is there I am pretty sure of it. I couldn't see any thing wrong in the Base class or subclasses code you updated. – Snicolas Nov 21 '12 at 10:44
  • @TobiasMoeThorstensen was this issue solved by you because i am running through the same problem – N Jay Sep 19 '13 at 19:36
  • @NaderAyyad Yes, I solved this issue, mainly by not keeping references to context's. I suggest you try to set them to `null` after you are done using them. – Tobias Moe Thorstensen Sep 20 '13 at 11:55

1 Answers1

9

Do you use static variables to cache big resources?
If yes then that's a common mistake in Android apps to use activity context to load such resources. This leads to sustain activities and all their resources even though they are not needed any more.
To fix this use application context to load such resources!

You can refer to this Android developers blog post for more details.

verybadalloc
  • 5,768
  • 2
  • 33
  • 49
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • What do you define as Big resources? `Bitmaps`? I'm using `getApplicationContext()` when loading Bitmaps from a `SQLite database`. And my Activity context reference when loading string from string.xml file. Is it best practice to always use `getApplicationContext()` ? – Tobias Moe Thorstensen Nov 21 '12 at 10:53
  • 4
    No the key word here is static. You should not keep static references to Activities, Contexts, resources. – Snicolas Nov 21 '12 at 11:08
  • @TobiasMoeThorstensen: so what exactly was the problem? – Vit Khudenko Nov 22 '12 at 09:45
  • 1
    @Arhimed There is many issues, but why I accept this answer is because it gave me some hints regardng the difference between `Application Context` and `Activity Context` Also I used a static inner class, to handle UI updates from a Thread. Currently I try to fix the context issues, as we speak. – Tobias Moe Thorstensen Nov 22 '12 at 09:48