Rob*_*Rob 21 android memory-leaks gallery
My app shows a list of 9 categories and each category displays a Gallery-based coverflow (graciously offered by Neil Davies here) with images of the selected category.
The images are fetched from the Web, each ranging from 300K to 500K in size, and stored in an arrayList of Drawables. This data is bound to the coverflow using a BaseAdapter (code below).
Every time I exit the coverflow and go back to the list of categories, I clear the arrayList (again, code below).
In scenario 1, my arrayList contains 5 Drawables. In this scenario, I can freely browse all the categories and show their images. During my test I cycled through all the categories for 5 times, which seems enough to determine that there is no problem.
在方案2中,我的arrayList包含10个drawable.在这种情况下,我在浏览第5或第6个类别中的图像时遇到OutOfMemoryError异常:
07-13 08:38:21.266: ERROR/dalvikvm-heap(2133): 819840-byte external allocation too large for this process. 07-13 08:38:21.266: ERROR/(2133): VM won't let us allocate 819840 bytes 07-13 08:38:21.277: DEBUG/skia(2133): --- decoder->decode returned false 07-13 08:38:21.287: WARN/dalvikvm(2133): threadid=25: thread exiting with uncaught exception (group=0x4001b188) 07-13 08:38:21.296: ERROR/AndroidRuntime(2133): Uncaught handler: thread Thread-64 exiting due to uncaught exception 07-13 08:38:21.308: ERROR/AndroidRuntime(2133): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 07-13 08:38:21.308: ERROR/AndroidRuntime(2133): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 07-13 08:38:21.308: ERROR/AndroidRuntime(2133): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:459) 07-13 08:38:21.308: ERROR/AndroidRuntime(2133): at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323) 07-13 08:38:21.308: ERROR/AndroidRuntime(2133): at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697) 07-13 08:38:21.308: ERROR/AndroidRuntime(2133): at android.graphics.drawable.Drawable.createFromStream(Drawable.java:657)
这对我来说没有意义.如果我泄漏内存,我本来期望在方案1中的某个时刻崩溃,但是我经历了很多次并且没有崩溃.我还使用了Eclipse的Memory Analyzer插件,它没有任何潜在的罪魁祸首.
如果系统无法处理10个图像,例如在scenarion 2中,我本来应该在第一个类别中崩溃,但是我只在5或6个类别后崩溃.
一些代码:
Coverflow的适配器功能:
public int getCount() {
return DataManager.getInstance().getImageBufferInstance().getImageArraySize();
}
public Object getItem(int position) {
return DataManager.getInstance().getImagesBuffer().get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i;
if (convertView == null)
i = new ImageView(mContext);
else
i = (ImageView)convertView;
Drawable bufferedImage = (Drawable)getItem(position);
Log.v("getView", "position: " + position);
i.setImageDrawable(bufferedImage);
i.setLayoutParams(new CoverFlow.LayoutParams(Utils.getInstance().getScreenWidth() / 2,
Utils.getInstance().getScreenHeight() / 2));
i.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
try{
//Make sure we set anti-aliasing otherwise we get jaggies
BitmapDrawable drawable = (BitmapDrawable) i.getDrawable();
drawable.setAntiAlias(true);
}
catch (Exception e)
{
Log.v("getView", "Exception: " + e.toString());
}
return i;
}
Run Code Online (Sandbox Code Playgroud)
在输入类别时填充数据源:
for (int i = 0; i < ImageBuffer.getInstance().getImageArraySize(); i++)
{
String imageUrl = ImageBuffer.getInstance().getImageUrl(i);
Log.v("Initial", imageUrl);
Drawable fullImage = AsyncImageLoader.getInstance().loadImageByUrl(imageUrl);
ImageBuffer.getInstance().getImages().add(i, fullImage);
}
Run Code Online (Sandbox Code Playgroud)
退出类别时清除数据源(在finish()中):
for (int i = 0; i < ImageBuffer.getInstance().getImageArraySize(); i++)
{
if (ImageBuffer.getInstance().images.get(i) != null)
{
ImageBuffer.getInstance().images.get(i).setCallback(null);
ImageBuffer.getInstance().images.set(i, null);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:
好的,我在我的coverflow上应用了Mathias的LogHeap函数,这里有一些输出.在加载第一个图库之前:
DEBUG/Application(5221): debug. ================================= DEBUG/Application(5221): debug.heap native: allocated 6.20MB of 6.28MB (0.07MB free) in [com.example.Coverflow] DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (0.00MB free) DEBUG/dalvikvm(5221): GC freed 4558 objects / 638152 bytes in 84ms DEBUG/dalvikvm(5221): GC freed 17 objects / 808 bytes in 67ms
进入第一个画廊后:
DEBUG/Application(5221): debug. ================================= DEBUG/Application(5221): debug.heap native: allocated 14.90MB of 16.89MB (0.07MB free) in [com.example.Coverflow] DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (1.00MB free) DEBUG/dalvikvm(5221): GC freed 357 objects / 50080 bytes in 68ms DEBUG/dalvikvm(5221): GC freed 353 objects / 27312 bytes in 67ms
在现有第一个画廊后:
DEBUG/Application(5221): debug. ================================= DEBUG/Application(5221): debug.heap native: allocated 14.83MB of 16.89MB (0.11MB free) in [com.example.Coverflow] DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (1.00MB free) DEBUG/dalvikvm(5221): GC freed 330 objects / 17920 bytes in 77ms DEBUG/dalvikvm(5221): GC freed 13 objects / 760 bytes in 67ms
进入第五个画廊后:
DEBUG/Application(5221): debug. ================================= DEBUG/Application(5221): debug.heap native: allocated 16.80MB of 23.32MB (0.08MB free) in [com.example.Coverflow] DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (1.00MB free) DEBUG/dalvikvm(5221): GC freed 842 objects / 99256 bytes in 73ms DEBUG/dalvikvm(5221): GC freed 306 objects / 24896 bytes in 69ms
退出第五个画廊后:
DEBUG/Application(5221): debug. ================================= DEBUG/Application(5221): debug.heap native: allocated 16.74MB of 23.32MB (0.11MB free) in [com.example.Coverlow] DEBUG/Application(5221): debug.memory: allocated: 4.00MB of 24.00MB (1.00MB free) DEBUG/dalvikvm(5221): GC freed 331 objects / 18184 bytes in 68ms DEBUG/dalvikvm(5221): GC freed 60 objects / 3128 bytes in 68ms
进入图库时似乎分配了越来越多的内存,但退出后很少发布.我不能正确清理我的抽屉吗?对于我的arrayable of drawables中的每个元素,我调用setCallBack(null)并将该元素设置为null.这还不够吗?
渴望任何洞察力.
谢谢
Mat*_*adt 37
图像从Web获取,每个图像的大小从300K到500K,并存储在Drawables的arrayList中.
您从Web加载的图像的kb文件大小并不直接相关.由于它们被转换为位图,因此需要为常规ARGB图像计算每个图像的宽度*高度*4个字节.(px中的宽度和高度).
位图使用本机堆,通常不会在hprof中显示.hprof应该只显示对象的数量,即剩下的BitmapDrawables或Bitmaps.
我在我的应用程序中使用此代码输出应用程序和本机堆使用的当前使用的内存:
public static void logHeap(Class clazz) {
Double allocated = new Double(Debug.getNativeHeapAllocatedSize())/new Double((1048576));
Double available = new Double(Debug.getNativeHeapSize())/1048576.0);
Double free = new Double(Debug.getNativeHeapFreeSize())/1048576.0);
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(2);
Log.d(APP, "debug. =================================");
Log.d(APP, "debug.heap native: allocated " + df.format(allocated) + "MB of " + df.format(available) + "MB (" + df.format(free) + "MB free) in [" + clazz.getName().replaceAll("com.myapp.android.","") + "]");
Log.d(APP, "debug.memory: allocated: " + df.format(new Double(Runtime.getRuntime().totalMemory()/1048576)) + "MB of " + df.format(new Double(Runtime.getRuntime().maxMemory()/1048576))+ "MB (" + df.format(new Double(Runtime.getRuntime().freeMemory()/1048576)) +"MB free)");
System.gc();
System.gc();
// don't need to add the following lines, it's just an app specific handling in my app
if (allocated>=(new Double(Runtime.getRuntime().maxMemory())/new Double((1048576))-MEMORY_BUFFER_LIMIT_FOR_RESTART)) {
android.os.Process.killProcess(android.os.Process.myPid());
}
}
Run Code Online (Sandbox Code Playgroud)
我在开发期间开始或完成一项活动时调用.
logHeap(this.getClass());
Run Code Online (Sandbox Code Playgroud)
这里有一些信息链接 - 通常这里有很多关于这个主题的主题.
这里也是Romain Guy(Android Framework工程师)关于软引用,弱引用,简单缓存,图像处理的有用幻灯片:http: //docs.huihoo.com/google/io/2009/Th_0230_TurboChargeYourUI-HowtomakeyourAndroidUIfastandefficient.pdf
| 归档时间: |
|
| 查看次数: |
31405 次 |
| 最近记录: |