找出资源去向的更好方法?
我的应用程序出现内存泄漏。所以我自然想要修复它。问题是要么我不知道如何使用 DDMS 和内存分配工具,要么它们都是垃圾(或两者兼而有之)。所以我想知道是否有另一种方法可以弄清楚我的所有资源都在哪里使用,或者是否有人可以启发我如何使用 DDMS 工具。
PS:是的,我知道我必须单击 DDMS 中的调试按钮,然后引发 HPROF 转储和/或使用更新堆按钮并执行 GC。我可以查看两者的详细信息,但看不到我创建的任何对象。简而言之,我无法阅读我正在查看的内容。
非常感谢任何帮助或启发。
~Aedon
编辑 1:
我在自定义视图中的绘图方法中添加了一些日志记录。经过一番实验,我发现内存泄漏似乎来自于这种方法。
/** 更新后台的独立于仪表的静态缓冲区缓存。 */
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);
}
现在,在我的应用程序中进行一些摆弄之后,我设法导致了这个错误:
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)
错误本身是有道理的。我的内存不足了。没有意义的是我试图制作的位图是 221px x 221px,但显然是 19528kb。如果我的数学正确的话,221 * 221 = 48841 * 4 = 195364 字节 = 190.7kb。这根本没有任何意义。任何人,请看一下,看看你能找到什么。顺便说一句,错误中的相关行如下(来自重新生成方法)
mBackground = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
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);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,我认为 Dalvik 消息显示了错误的单位,而 GraphicsJNI 错误是正确的:
请记住,您可以捕获内存错误:
如果您的位图始终大小相同,我建议重新使用它们。如果您相当快地创建和销毁位图,则您将面临超过垃圾收集器并进入此状态的风险。
- 编辑 -
至于你原来的问题。在查找内存泄漏时,我通常会执行以下操作。
初始化步骤
分析
您需要考虑您在这里看到的内容以及它对您的应用程序是否有意义。是否应该有 1000 个小内存分配?很可能不会。此时,您可以单击一个分配并准确查看导致分配的方法和行号。
另一种方法是为您的应用程序启用堆更新并使用堆资源管理器来跟踪分配。堆资源管理器不会告诉您分配来自哪里,但它会告诉您例如:
然后,您可以进入分配跟踪器并按大小对分配进行排序,以查看在何处执行 1k 分配。
First, I think the Dalvik message is showing the wrong units whereas the GraphicsJNI error is correct:
Keep in mind you can catch the memory error:
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
Analysis
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:
You can then go into the Allocation Tracker and sort allocations by size to see where you are performing 1k allocations.
我喜欢使用分配跟踪工具。
http://android-developers.blogspot.com/2009/02 /track-memory-allocations.html
我意识到这不是您要问的...
我发现以下有关 Android 内存泄漏的文档值得一读。
http://developer.android.com/resources/articles/avoiding-memory -leaks.html
...以及 http://android-developers.blogspot.com/search/label/Optimization
I like to use the allocation tracker tool.
http://android-developers.blogspot.com/2009/02/track-memory-allocations.html
I realize this isn't what you were asking about...
I've found the following documentation on Android memory leaks to be worth reading.
http://developer.android.com/resources/articles/avoiding-memory-leaks.html
...as well as the other posts on optimization at http://android-developers.blogspot.com/search/label/Optimization