【问题标题】:Android: java.lang.OutOfMemoryError: bitmap size exceeds VM budget [duplicate]Android:java.lang.OutOfMemoryError:位图大小超出VM预算[重复]
【发布时间】:2012-08-12 16:54:03
【问题描述】:

可能重复:
java.lang.OutOfMemoryError: bitmap size exceeds VM budget - Android

我目前正在开发一个 Android 应用程序,它显示从 URL 下载的图像并将它们放在 ListView 中。当它被点击时,会为点击的图像创建一个新的 ImageView。单击较小的图像(7kb)时,它运行良好。甚至可以正常运行到 200kb。但是比这更大的,我得到一个错误“应用程序已意外停止。请重试。”。查看 LogCat,问题似乎与 Android 内存不足有关。这个问题有方法解决吗?还是只是将图像的分辨率降低到 200kb 范围的问题?当然,图像大小不应该超过 1 或 2 兆字节?加载可能需要更长的时间,但不明白为什么会引发错误。

任何帮助将不胜感激!

Zoom.java

public class Zoom extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.gallery_zoom);

        String selection = getIntent().getExtras().getString("image");
        Toast.makeText(this, selection, Toast.LENGTH_LONG).show();

        new backgroundLoader().execute();
    }


    public class backgroundLoader extends AsyncTask<Void, Void, Void> {
        Bitmap bmp;

        @Override
        protected Void doInBackground(Void... params) {
            BitmapFactory.Options bmpOptions;
            bmpOptions = new BitmapFactory.Options();
            bmpOptions.inSampleSize = 1;
            bmp = LoadImage(getIntent().getExtras().getString("image"), bmpOptions);
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            ImageView image = (ImageView) findViewById(R.id.imageZoom);
            image.setImageBitmap(bmp);
            super.onPostExecute(result);
        }

    }

    private Bitmap LoadImage(String URL, BitmapFactory.Options options) {
        Bitmap bitmap = null;
        InputStream in = null;
        try {
            in = OpenHttpConnection(URL);
            bitmap = BitmapFactory.decodeStream(in, null, options);
            in.close();
        } catch (IOException e1) {
        }
        return bitmap;

    }

    private InputStream OpenHttpConnection(String strURL) throws IOException {
        InputStream inputStream = null;
        URL url = new URL(strURL);

        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        try {
            InputStream in = new BufferedInputStream(connection.getInputStream());
            return in;
        } catch (Exception exception) {
            exception.printStackTrace();
            return null;
        }
    }

}

LogCat 日志

08-13 07:35:01.798: E/dalvikvm-heap(1132): 48064000-byte external allocation too large for this process.
08-13 07:35:01.888: E/GraphicsJNI(1132): VM won't let us allocate 48064000 bytes
08-13 07:35:01.888: D/dalvikvm(1132): GC_FOR_MALLOC freed 1K, 54% free 2694K/5831K, external 2229K/3423K, paused 19ms
08-13 07:35:01.888: D/skia(1132): --- decoder->decode returned false
08-13 07:35:01.888: W/dalvikvm(1132): threadid=14: thread exiting with uncaught exception (group=0x40015560)
08-13 07:35:01.898: E/AndroidRuntime(1132): FATAL EXCEPTION: AsyncTask #1
08-13 07:35:01.898: E/AndroidRuntime(1132): java.lang.RuntimeException: An error occured while executing doInBackground()
08-13 07:35:01.898: E/AndroidRuntime(1132):     at android.os.AsyncTask$3.done(AsyncTask.java:200)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:274)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask.setException(FutureTask.java:125)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:308)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.lang.Thread.run(Thread.java:1019)
08-13 07:35:01.898: E/AndroidRuntime(1132): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-13 07:35:01.898: E/AndroidRuntime(1132):     at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at com.example.example.mobile.application.gallery.Zoom.LoadImage(Zoom.java:72)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at com.example.example.mobile.application.gallery.Zoom.access$0(Zoom.java:67)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at com.example.example.mobile.application.gallery.Zoom$backgroundLoader.doInBackground(Zoom.java:54)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at com.example.example.mobile.application.gallery.Zoom$backgroundLoader.doInBackground(Zoom.java:1)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
08-13 07:35:01.898: E/AndroidRuntime(1132):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
08-13 07:35:01.898: E/AndroidRuntime(1132):     ... 4 more
08-13 07:35:01.908: W/ActivityManager(61):   Force finishing activity com.example.example.mobile.application/.gallery.Zoom

【问题讨论】:

  • 此页面右侧的“相关”列没有帮助?
  • 看起来您正在尝试加载 45mb 的图片...这在许多手机上都不起作用
  • 我在 SO 上已经好几次了,我每天都会看到大约 2、3 个关于这个问题的问题...在发布之前做一些研究,您可能已经知道答案了...
  • @IncrediApp 这就是我不明白的一点,我要加载的图像是 800KB 而不是 45mb?

标签: android android-layout


【解决方案1】:

我建议您考虑一种更复杂的缓存方法,以确保您永远不会达到 VM 的内存限制。 Android 自己的高级课程网站是资源的绝佳去处。本教程最关键的部分是创建一个 LRUCache,它的限制为 VM 内存限制的百分比。

http://developer.android.com/training/displaying-bitmaps/index.html

【讨论】:

    【解决方案2】:

    首先您必须知道您的 200Kb 是压缩的 jpg 格式。 Android 以位图非压缩格式存储图像。根据照片的大小,每张照片最多可以添加几兆字节。

    要尽量减少问题,您可以查看 BitmapFactry insamplesize 方法:

    http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inSampleSize

    它允许您以较低的分辨率(2 的幂)打开图像。

    也尝试积极调用:

    mybitmap = null;
    System.gc;
    System.runFinalization;
    System.gc;
    

    每次都可以。

    【讨论】:

      【解决方案3】:

      一些想法

      1. 不要在 AsyncTask 中保留对位图的引用,通过将位图定义为参数而不是 Void 来正确使用它。学习here

      2. 您可能需要回收位图。请参阅 Android 开发人员培训here,了解如何处理位图。

      3. 学习记忆分析工具(MAT)here

      【讨论】:

        猜你喜欢
        • 2012-08-19
        • 2011-07-27
        • 2012-11-12
        • 2011-02-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多