Better way of finding out where resources are going?-Collection of common programming errors
I have a memory leak in my app. So naturally I want to fix it. The issue is either I don’t know how to use the DDMS and memory allocation tools or they are peices of crap (or both). So I’m wondering if there is another way I can figure out where all of my resources are being used or if someone can enlighten me on how to use the DDMS tools.
PS: Yes, I know I have to click the debug button in the DDMS and then cause a HPROF dump and/of use the Update heap button and do a GC. I can view the details of both but I can’t see any of the objects I have created. In short I can’t read what I’m viewing.
Any help or enlightenment is greatly appreciated.
~Aedon
Edit 1:
I added some logging throughout the drawing methods in my custom views. After some experimentation, I discoverd that the memory leak seams to be coming from this method.
/** Update the gauge independent static buffer cache for the background. */
private void regenerate() {
mNeedRegen = false;
// Prevent memory leaks by disposing of old bitmaps.
if (mBackground != null) { mBackground.recycle(); mBackground = null; }
// Our new drawing area
Log.d(TAG, getWidth() + "\t" + getHeight());
mBackground = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas backCanvas = new Canvas(mBackground);
float scale = (float)getWidth();
backCanvas.scale(scale, scale);
drawRim(backCanvas);
drawFace(backCanvas);
drawTitle(backCanvas);
if (!(this instanceof EmptySpace)) { drawGroupIcon(backCanvas); }
regenerateBackground(backCanvas);
}
Now after some fiddling around in my app, I managed to cause this error:
dalvikvm-heap E 195364-byte external allocation too large for this process.
2935 dalvikvm E Out of memory: Heap Size=4871KB, Allocated=2636KB, Bitmap Size=19528KB
2935 GraphicsJNI E VM won't let us allocate 195364 bytes
2935 AndroidRuntime D Shutting down VM
2935 dalvikvm W threadid=1: thread exiting with uncaught exception (group=0x400259f8)
2935 AndroidRuntime E FATAL EXCEPTION: main
2935 AndroidRuntime E java.lang.OutOfMemoryError: bitmap size exceeds VM budget
2935 AndroidRuntime E at android.graphics.Bitmap.nativeCreate(Native Method)
2935 AndroidRuntime E at android.graphics.Bitmap.createBitmap(Bitmap.java:574)
2935 AndroidRuntime E at com.android.appion.arm.widgets.GaugeBase.regenerate(GaugeBase.java:239)
2935 AndroidRuntime E at com.android.appion.arm.widgets.GaugeBase.onSizeChanged(GaugeBase.java:86)
2935 AndroidRuntime E at android.view.View.setFrame(View.java:7101)
2935 AndroidRuntime E at android.view.View.layout(View.java:7028)
2935 AndroidRuntime E at android.widget.GridView.setupChild(GridView.java:1316)
2935 AndroidRuntime E at android.widget.GridView.makeAndAddView(GridView.java:1222)
2935 AndroidRuntime E at android.widget.GridView.makeRow(GridView.java:265)
2935 AndroidRuntime E at android.widget.GridView.fillSpecific(GridView.java:463)
2935 AndroidRuntime E at android.widget.GridView.layoutChildren(GridView.java:1122)
2935 AndroidRuntime E at android.widget.AbsListView.onLayout(AbsListView.java:1147)
2935 AndroidRuntime E at android.view.View.layout(View.java:7034)
2935 AndroidRuntime E at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1249)
2935 AndroidRuntime E at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1125)
2935 AndroidRuntime E at android.widget.LinearLayout.onLayout(LinearLayout.java:1042)
2935 AndroidRuntime E at android.view.View.layout(View.java:7034)
2935 AndroidRuntime E at android.widget.SlidingDrawer.onLayout(SlidingDrawer.java:331)
2935 AndroidRuntime E at android.view.View.layout(View.java:7034)
2935 AndroidRuntime E at android.widget.RelativeLayout.onLayout(RelativeLayout.java:909)
2935 AndroidRuntime E at android.view.View.layout(View.java:7034)
2935 AndroidRuntime E at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
2935 AndroidRuntime E at android.view.View.layout(View.java:7034)
2935 AndroidRuntime E at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1249)
2935 AndroidRuntime E at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1125)
2935 AndroidRuntime E at android.widget.LinearLayout.onLayout(LinearLayout.java:1042)
2935 AndroidRuntime E at android.view.View.layout(View.java:7034)
2935 AndroidRuntime E at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
2935 AndroidRuntime E at android.view.View.layout(View.java:7034)
2935 AndroidRuntime E at android.view.ViewRoot.performTraversals(ViewRoot.java:1049)
2935 AndroidRuntime E at android.view.ViewRoot.handleMessage(ViewRoot.java:1744)
2935 AndroidRuntime E at android.os.Handler.dispatchMessage(Handler.java:99)
2935 AndroidRuntime E at android.os.Looper.loop(Looper.java:144)
2935 AndroidRuntime E at android.app.ActivityThread.main(ActivityThread.java:4937)
2935 AndroidRuntime E at java.lang.reflect.Method.invokeNative(Native Method)
2935 AndroidRuntime E at java.lang.reflect.Method.invoke(Method.java:521)
2935 AndroidRuntime E at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
2935 AndroidRuntime E at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
2935 AndroidRuntime E at dalvik.system.NativeStart.main(Native Method)
The error itself makes sense. I ran out of memory. What doesn’t make sense is the bitmap I’m trying to make is 221px by 221px but aparently is 19528kb. If my math is right 221 * 221 = 48841 * 4 = 195364 bytes = 190.7kb. This doesn’t make any sense at all. Anywho, please take a look and see what you can find. BTW, the line in question from the error is the following (from the regenerate method)
mBackground = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
-
First, I think the Dalvik message is showing the wrong units whereas the GraphicsJNI error is correct:
dalvikvm E Out of memory: Heap Size=4871KB, Allocated=2636KB, Bitmap Size=19528KB 2935
GraphicsJNI E VM won’t let us allocate 195364 bytesKeep in mind you can catch the memory error:
try{ mBackground = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); } catch(OutOfMemoryError e){ //do something }
If your bitmaps are always the same size, I would recommend re-using them. If you are creating and destroying bitmaps fairly quickly, you run the risk of out-pacing the Garbage Collector and getting into this state.
–Edit– As for your original question. I typically do the following when looking for a memory leak.
Initialization Steps
- Make sure your app is set to be debuggable in the manifest
- Launch your app, open DDMS and select your application.
- Select the Allocation Tracker view and Start Tracking
Analysis
- Let your app run, or perform some specific activities in your app that are causing memory issues.
- Click “Get Allocations” to update the tracker. You can now stop tracking if you like.
- In the filter, type your application name to narrow down the results.
You need to think about what you are seeing here and whether it makes sense for your application. Should there be 1000’s of small memory allocations? Most likely not. At this point you can click on an allocation and see exactly which method and line number is causing the allocation.
Another route to take is to enable heap updates for your app and use the heap explorer to track allocations. The heap explorer does not tell you where the allocation is coming from, but what it will tell you is that for instance:
The number of 1k allocations is growing and never shrinking.
You can then go into the Allocation Tracker and sort allocations by size to see where you are performing 1k allocations.
Originally posted 2013-11-27 11:51:33.