【问题标题】:Out of memory exception in case of simple static gallery简单静态库的内存不足异常
【发布时间】:2013-03-15 10:34:53
【问题描述】:

我正在使用一个简单的静态图片库,我在其中加载了至少 28 张不同大小的图片,每个图片都小于 150kb。

我注意到这里有两个问题:

1) 慢速滚动 2) 当我两次参加这个活动时出现内存不足异常。

任何人指导我这里的问题是什么以及如何解决它?

任何帮助将不胜感激

原木猫:

03-15 15:32:55.899: E/AndroidRuntime(14662): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:563)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:439)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:697)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.content.res.Resources.loadDrawable(Resources.java:1709)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.content.res.Resources.getDrawable(Resources.java:581)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.ImageView.resolveUri(ImageView.java:501)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.ImageView.setImageResource(ImageView.java:280)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.tackfu.Art$ImageAdapter.getView(Art.java:84)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.AbsListView.obtainView(AbsListView.java:1515)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.GridView.makeAndAddView(GridView.java:1269)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.GridView.makeRow(GridView.java:315)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.GridView.fillDown(GridView.java:268)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.GridView.fillGap(GridView.java:235)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.AbsListView.trackMotionScroll(AbsListView.java:4063)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.widget.AbsListView.onTouchEvent(AbsListView.java:2471)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.View.dispatchTouchEvent(View.java:3885)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:903)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:942)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1750)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1135)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.app.Activity.dispatchTouchEvent(Activity.java:2096)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1734)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2216)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.view.ViewRoot.handleMessage(ViewRoot.java:1887)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.os.Handler.dispatchMessage(Handler.java:99)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.os.Looper.loop(Looper.java:130)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at android.app.ActivityThread.main(ActivityThread.java:3687)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at java.lang.reflect.Method.invokeNative(Native Method)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at java.lang.reflect.Method.invoke(Method.java:507)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
03-15 15:32:55.899: E/AndroidRuntime(14662):    at dalvik.system.NativeStart.main(Native Method)

活动代码:

 @Override
        public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
            setContentView(R.layout.art);

 GridView gridview = (GridView) findViewById(R.id.gridv
 gridview.setAdapter(new ImageAdapter(this));

}

 public class ImageAdapter extends BaseAdapter {
            private Context mContext;

            public ImageAdapter(Context c) {
                mContext = c;
            }

            public int getCount() {
                return mThumbIds.length;
            }

            public Object getItem(int position) {
                return null;
            }

            public long getItemId(int position) {
                return 0;
            }

            // create a new ImageView for each item referenced by the Adapter
            public View getView(int position, View convertView, ViewGroup parent) {
                ImageView imageView;
                if (convertView == null) {  // if it's not recycled, initialize some attributes
                    imageView = new ImageView(mContext);
                    imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
                    imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                    imageView.setPadding(8, 8, 8, 8);
                } else {
                    imageView = (ImageView) convertView;
                }

                imageView.setImageResource(mThumbIds[position]);
                return imageView;
            }

            // references to our images
            private Integer[] mThumbIds = {
                    R.drawable.i1, R.drawable.i2,
                    R.drawable.i3, R.drawable.i4,
                    R.drawable.i5, R.drawable.i6,
                    R.drawable.i7, R.drawable.i8,
                    R.drawable.i9, R.drawable.i10,
                    R.drawable.i11, R.drawable.i12,
                    R.drawable.i13,R.drawable.i14,
                    R.drawable.i15,R.drawable.i16,
                    R.drawable.i17,R.drawable.i18,
                    R.drawable.i19,R.drawable.i20,
                    R.drawable.i21, R.drawable.i22,
                    R.drawable.i23, R.drawable.i24,
                    R.drawable.i26, R.drawable.i28,
                    R.drawable.i29, R.drawable.i30
            };
        }

【问题讨论】:

  • 你看过这篇文章了吗stackoverflow.com/questions/1949066/…
  • 关于内存不足,如果你启动你的活动,然后完成它,然后重新启动它,就会出现内存不足我认为你在某个地方有泄漏
  • 如果您指出泄漏,我将不胜感激。
  • 我只能给你一个建议,像 myvar = null 一样粗暴地取消引用 activity.finish 中的所有内容并调用 System.gc()

标签: android gridview imageview android-gallery


【解决方案1】:

在不使用时回收位图。使用视图支架以获得更好的性能。 http://www.youtube.com/watch?v=wDBM6wVEO70。我建议你看看链接。无论适用于 listview 也适用于 gridview 和视频讨论它。该视频还对视图支架进行了讨论,这正是您应该使用的以避免内存泄漏。

http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html 也有关于避免内存泄漏的讨论。

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html。请参阅将缩小版本加载到内存中

部分

使用 MAT Analyzer 检查内存泄漏。 http://www.youtube.com/watch?v=_CruQY55HOk.

http://developer.android.com/training/articles/perf-tips.html 上考虑一些提示。

【讨论】:

  • 谢谢 raghunandan,你有详细的答案,它帮助我解决了这个问题。
  • 很高兴它有帮助。您正在显示 28 张图像。有些应用程序有更多。所以显示 28 张图像不应该给你内存不足的错误。如果你有效地加载它们,你应该不会耗尽内存。
【解决方案2】:

28 张 150KB 大小的图像大约是 ~4MB RAM。加上应用程序数据,它不适合小堆。你可以设置large heap into manifest:

android:largeHeap="true"

但是这种方法看起来是一种解决方法,因为您有无限的内存并且图像数量的增加可能会再次导致此错误。您还应该使用延迟加载或根据设备屏幕大小调整图像大小。

【讨论】:

  • youtube.com/watch?v=_CruQY55HOk。在视频中,伙计们给出了一个关于 android:largeHeap="true" 的警告,说只是因为需要大堆不要使用这个。堆大小越大,垃圾收集就越频繁。
  • 你是对的,大堆不是解决方案。感谢您的链接。
  • 最佳答案!我有一个类似的问题(试图为十几个图像分配约 5 MB)并且无法解决几个小时。这个参数是我需要的。
【解决方案3】:

滚动慢的原因很简单。每次创建视图时,您都会在 UI 线程中加载图像。您应该将加载委托给另一个低优先级的线程。如果您愿意,您可以在 UI 线程中加载缩略图以快速显示某些内容,然后在后台加载全分辨率。

请记住,Android 有很多巧妙的技巧可以让您的应用变得漂亮,但您必须明智地使用它们。例如,Android 在所谓的绘图缓存中缓存静态视图,但在 ImgaeViews 的情况下,它是没有意义的,因为它需要额外的内存并且什么都不提供。使用硬件加速 UI 会使用更多内存,因为每个视图缓存都是在二次幂纹理上绘制的。这意味着 100x35px 按钮将占用 128x64x4 字节的额外内存。 Android 也会尝试使用某种抗锯齿功能,例如线性纹理采样器 - 这很好,但会占用大量 CPU 时间,您可能需要将其关闭。

通过 setImageResource 加载图像几乎没有控制权。您可能希望自己加载图像,以便更精确地控制加载和卸载。您还可以稍微缓存图像。 LRU 缓存是为此类用途而设计的类的一个很好的例子:http://developer.android.com/reference/android/util/LruCache.html。您可以加载当前图像并在左侧预加载一张,在右侧预加载一张。当用户返回上一张图片时,您将把它保存在内存中。

另外,如果你想使用蛮力,你可以使用 NativeBuffer 缓存你的图像:http://code.google.com/p/native-buffer/。它会迫使你重新设计你的画廊,但它会大大加快图像密集型应用程序的速度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    相关资源
    最近更新 更多