我已经开发了一个Android应用程序,而我正在进行电话应用程序开发,一切似乎都很好,并且您想宣告胜利并出货,但是您知道必须存在一些内存和资源泄漏在那里; Android上只有16mb的堆,而且显然很容易在Android应用中泄漏。
我一直在环顾四周,到目前为止,我们只能挖掘有关“ hprof”和“ traceview”的信息,而且都没有得到很多好评。
您遇到或开发了哪些工具或方法,并希望在OS项目中共享这些工具或方法?
我已经开发了一个Android应用程序,而我正在进行电话应用程序开发,一切似乎都很好,并且您想宣告胜利并出货,但是您知道必须存在一些内存和资源泄漏在那里; Android上只有16mb的堆,而且显然很容易在Android应用中泄漏。
我一直在环顾四周,到目前为止,我们只能挖掘有关“ hprof”和“ traceview”的信息,而且都没有得到很多好评。
您遇到或开发了哪些工具或方法,并希望在OS项目中共享这些工具或方法?
Answers:
我发现开发Android应用程序时最常见的错误之一是“ java.lang.OutOfMemoryError:位图大小超出VM预算”错误。我在更改方向后频繁使用大量位图在活动中发现此错误:活动被销毁,再次创建,布局从XML“膨胀”,消耗了位图可用的VM内存。
垃圾回收器未正确释放先前活动布局上的位图,因为它们已经交叉引用了其活动。经过多次实验,我发现了一个很好的解决方案。
首先,在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()方法,将引用传递给父View,然后执行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()方法以递归方式探索视图树,并:
PageAdapter
并且我正在处理此错误:(
主要面向未来的Google旅行者:
不幸的是,大多数Java工具都不适合该任务,因为它们仅分析JVM-Heap。但是,每个Android应用程序也都有一个本机堆,该堆也必须符合〜16 MB的限制。例如,它通常用于位图数据。因此,即使您使用大量可绘制对象,即使您的JVM-Heap的内存约为3 MB,您也可以很容易地遇到内存不足错误。
从@ hp.android答案运作良好,如果你只是用位图背景的工作,但是,在我的情况,我有一个BaseAdapter
提供一组ImageView
为A S GridView
。我unbindDrawables()
按照建议修改了方法,使条件为:
if (view instanceof ViewGroup && !(view instanceof 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
s管理的位图不是背景。因此,我添加了以下内容。这不是理想的方法,但可以:
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上运行Android的Valgrind(评论67)。