哪些Android工具和方法最适合查找内存/资源泄漏?
我已经开发了一个Android应用程序,而我正处于一个电话应用程序开发的地步,一切似乎都运行良好,你想宣布胜利和发布,但是你知道只需要一些内存和资源泄漏在那里; Android上只有16MB的堆,而且在Android应用中显然很容易泄漏。
我一直在环顾四周,到目前为止只能挖掘'hprof'和'traceview'的信息,也没有得到很多有利的评论。
您可能在操作系统项目中遇到或开发了哪些工具或方法,并关心共享?
我发现开发Android应用程序最常见的错误之一是“java.lang.OutOfMemoryError:Bitmap Size Exceeded VM Budget”错误。 在改变方向之后,我发现这个错误在使用大量位图的活动上很活跃:活动被破坏,再次创建,布局从耗费虚拟机内存的XML中“膨胀”,可用于位图。
之前的活动布局上的位图由垃圾收集器不正确地解除分配,因为它们已经交叉引用了它们的活动。 经过多次实验,我发现了一个很好的解决方案。
首先,在你的XML布局的父视图中设置“id”属性:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/RootView" > ...
然后,在Activity的onDestroy()方法中,调用unbindDrawables()方法,向父视图传递一个refence,然后执行System.gc()
@Override protected void onDestroy() { super.onDestroy(); unbindDrawables(findViewById(R.id.RootView)); System.gc(); } private void unbindDrawables(View view) { if (view.getBackground() != null) { view.getBackground().setCallback(null); } if (view instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) { unbindDrawables(((ViewGroup) view).getChildAt(i)); } ((ViewGroup) view).removeAllViews(); } }
这个unbindDrawables()方法递归地探索视图树,并且:
- 删除所有背景drawables上的回调
- 删除每个视图组的子视图
获取Eclipse内存分析器( http://www.eclipse.org/mat/ )检查http://kohlerm.blogspot.com/2010/02/android-memory-usage-analysis-slides.html和http::// kohlerm.blogspot.com/search/label/memory
大部分来自未来的Google旅行者:
大多数java工具不幸的不适合这个任务,因为他们只分析JVM-Heap。 每个Android应用程序也有一个本地堆,但也必须适合〜16 MB的限制。 例如,它通常用于位图数据。 因此,即使您的JVM-Heap在3 MB左右,如果您使用了大量绘图工具,也可以很容易地运行到Out Of Memory错误。
@ hp.android的答案效果很好,如果你只是使用位图背景,但在我的情况下,我有一个BaseAdapter
提供一组GridView
的ImageView
。 我建议修改unbindDrawables()
方法,以便条件是:
if (view instanceof ViewGroup && !(view instanceof AdapterView)) { ... }
但问题是递归方法从不处理AdapterView
的子AdapterView
。 为了解决这个问题,我做了以下工作:
if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; for (int i = 0; i < viewGroup.getChildCount(); i++) unbindDrawables(viewGroup.getChildAt(i)); if (!(view instanceof AdapterView)) viewGroup.removeAllViews(); }
以便AdapterView
的子项仍然处理 – 该方法不会尝试删除所有子项(不受支持)。
但是这并不能解决这个问题,因为ImageView
管理一个不是它们背景的位图。 因此我添加了以下内容。 这不是理想的,但它的工作原理:
if (view instanceof ImageView) { ImageView imageView = (ImageView) view; imageView.setImageBitmap(null); }
总体来说, unbindDrawables()
方法是:
private void unbindDrawables(View view) { if (view.getBackground() != null) view.getBackground().setCallback(null); if (view instanceof ImageView) { ImageView imageView = (ImageView) view; imageView.setImageBitmap(null); } else if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; for (int i = 0; i < viewGroup.getChildCount(); i++) unbindDrawables(viewGroup.getChildAt(i)); if (!(view instanceof AdapterView)) viewGroup.removeAllViews(); } }
我希望有一个更原则的方法来释放这些资源。
在Android的内存管理方面有很好的Google I / O讲座(2011),以及有关内存分析工具+技术的详细信息:
http://www.youtube.com/watch?v=_CruQY55HOk
Valgrind已被移植到Android(由Mozilla赞助)。 请参阅Android上的Valgrind – 目前状态和支持在ARM上运行Valgrind for Android (评论67)。
那么,这些工具钩与Android使用的独特格式..我想你可能不满意的是底层的测试代码框架在使用..
您是否使用Android Mock Framework尝试过模拟测试代码区域?