【问题标题】:Better way of finding out where resources are going?找出资源去向的更好方法?
【发布时间】:2011-05-13 18:19:49
【问题描述】:

我的应用程序出现内存泄漏。所以很自然地我想修复它。问题是我不知道如何使用 DDMS 和内存分配工具,或者它们是垃圾(或两者兼而有之)。所以我想知道是否有另一种方法可以找出我所有资源的使用情况,或者是否有人可以指导我如何使用 DDMS 工具。

PS:是的,我知道我必须单击 DDMS 中的调试按钮,然后导致 HPROF 转储和/或使用更新堆按钮并​​执行 GC。我可以查看两者的详细信息,但看不到我创建的任何对象。简而言之,我无法阅读我正在查看的内容。

非常感谢任何帮助或启发。

~艾顿

编辑 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 bytes = 190.7kb。这根本没有任何意义。任何人,请看一看,看看你能找到什么。顺便说一句,错误中有问题的行如下(来自 regenerate 方法)

mBackground = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);

【问题讨论】:

    标签: android memory-leaks memory-management ddms


    【解决方案1】:

    首先,我认为 Dalvik 消息显示了错误的单位,而 GraphicsJNI 错误是正确的:

    dalvikvm E 内存不足:堆 大小=4871KB,分配=2636KB,位图 大小=19528KB 2935
    GraphicsJNI E VM 不会让我们 分配 195364 字节

    请记住,您可以捕获内存错误:

    try{
        mBackground = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
    } catch(OutOfMemoryError e){
        //do something
    }
    

    如果您的位图大小始终相同,我建议您重新使用它们。如果您以相当快的速度创建和销毁位图,则可能会超过垃圾收集器并进入此状态。

    --编辑-- 至于你原来的问题。在查找内存泄漏时,我通常会执行以下操作。

    初始化步骤

    1. 确保您的应用在清单中设置为可调试
    2. 启动您的应用,打开 DDMS 并选择您的应用。
    3. 选择分配跟踪器视图并开始跟踪

    分析

    1. 让您的应用运行,或在您的应用中执行一些会导致内存问题的特定活动。
    2. 单击“获取分配”以更新跟踪器。您现在可以根据需要停止跟踪。
    3. 在过滤器中,输入您的应用程序名称以缩小结果范围。

    您需要考虑您在此处看到的内容以及它是否对您的应用有意义。应该有 1000 个小内存分配吗?很可能不是。此时,您可以单击分配,并准确查看导致分配的方法和行号。

    另一种方法是为您的应用启用堆更新并使用堆资源管理器来跟踪分配情况。堆资源管理器不会告诉您分配的来源哪里,但它会告诉您例如:

    1k 分配的数量是 成长,永不萎缩。

    然后您可以进入分配跟踪器并按大小对分配进行排序,以查看执行 1k 分配的位置。

    【讨论】:

    • 太棒了,先生!非常感谢您的详细介绍。
    • 尽管如此,我在看到那个错误时一定是被交叉眼了。我无法相信在通过错误查看所有时间之后,我没有看到真正的分配大小就坐在那里。
    • 日志很吵,所以不要难过。内存分析可能需要几次尝试和一些头脑风暴才能真正深入了解,Google 提供的工具在所有方面都相当不错。
    【解决方案2】:

    我喜欢使用分配跟踪工具。

    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上的其他优化帖子

    【讨论】:

    猜你喜欢
    • 2013-07-24
    • 2018-04-25
    • 1970-01-01
    • 2013-01-09
    • 1970-01-01
    • 2019-11-18
    • 2012-03-01
    • 2012-06-20
    • 1970-01-01
    相关资源
    最近更新 更多