Android:java.lang.OutOfMemoryError:无法分配带有2097152个空闲字节的23970828字节分配和2MB直到OOM

问题描述 投票:289回答:28

我想在已存储的SD卡中显示ImageView中的Bitmap图像。运行后我的应用程序崩溃并导致OutOfMemoryError错误:

(java.lang.OutOfMemoryError:无法分配带有2097152个空闲字节的23970828字节分配和2MB直到OOM)

我不知道或为什么它的内存不足。我认为我的图像尺寸非常大,所以我试图改变它。

Iterator<String> it = imageArray.iterator();
while (it.hasNext()) {
  Object element = it.next();
  String objElement = element.toString();
  Log.e("objElement ", " = " + objElement);
  final ImageView imageView = new ImageView (getContext());
  final ProgressBar pBar = new ProgressBar(getContext(), null, 
                                           android.R.attr.progressBarStyleSmall);
  imageView.setTag(it);
  pBar.setTag(it);

  imageView.setImageResource(R.drawable.img_placeholder);
  pBar.setVisibility(View.VISIBLE);

  if (objElement.endsWith(mp3_Pattern)) {
     Log.e("Mp3 ", " ends with ");
     pBar.setVisibility(View.GONE);
     imageView.setImageResource(R.drawable.audio_control);
  }
  if (objElement.endsWith(png_Pattern)) {
     Bitmap bitmap = BitmapFactory.decodeFile(objElement);
     int size = Math.min(bitmap.getWidth(), bitmap.getHeight());
     int x = (bitmap.getWidth() - size) / 2;
     int y = (bitmap.getHeight() - size) / 2;
     Bitmap bitmap_Resul = Bitmap.createBitmap(bitmap, x, y, size, size);
     Log.e("bitmap_Resul "," = "+ bitmap_Resul);

     if (bitmap_Resul != bitmap) {
        bitmap.recycle();
     }
     imageView.setImageBitmap(bitmap_Resul);
     Log.e("png_Pattern ", " ends with ");
     Log.e(" bitmap "," = " + bitmap);
  }

  holder.linearLayout.addView(imageView);
  holder.linearLayout.addView(pBar);

日志猫信息:

08-27 14:11:15.307    1857-1857/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.example.tazeen.classnkk, PID: 1857
    java.lang.OutOfMemoryError: Failed to allocate a 23970828 byte allocation with 2097152 free bytes and 2MB until OOM
            at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
            at android.graphics.Bitmap.nativeCreate(Native Method)
            at android.graphics.Bitmap.createBitmap(Bitmap.java:812)
            at android.graphics.Bitmap.createBitmap(Bitmap.java:789)
            at android.graphics.Bitmap.createBitmap(Bitmap.java:709)
            at android.graphics.Bitmap.createBitmap(Bitmap.java:634)
            at com.example.tazeen.classnkk.AllPosts_Page$MyListAdapter.getView(AllPosts_Page.java:357)
            at android.widget.AbsListView.obtainView(AbsListView.java:2347)
            at android.widget.ListView.makeAndAddView(ListView.java:1864)
            at android.widget.ListView.fillDown(ListView.java:698)
            at android.widget.ListView.fillFromTop(ListView.java:759)
            at android.widget.ListView.layoutChildren(ListView.java:1659)
            at android.widget.AbsListView.onLayout(AbsListView.java:2151)
            at android.view.View.layout(View.java:15671)
            at android.view.ViewGroup.layout(ViewGroup.java:5038)
            at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
            at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
            at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
            at android.view.View.layout(View.java:15671)
            at android.view.ViewGroup.layout(ViewGroup.java:5038)
            at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
            at android.view.View.layout(View.java:15671)
            at android.view.ViewGroup.layout(ViewGroup.java:5038)
            at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1703)
            at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1557)
            at android.widget.LinearLayout.onLayout(LinearLayout.java:1466)
            at android.view.View.layout(View.java:15671)
            at android.view.ViewGroup.layout(ViewGroup.java:5038)
            at android.widget.FrameLayout.layoutChildren(FrameLayout.java:579)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:514)
            at android.view.View.layout(View.java:15671)
            at android.view.ViewGroup.layout(ViewGroup.java:5038)
            at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2086)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1843)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
            at android.view.Choreographer.doCallbacks(Choreographer.java:580)
            at android.view.Choreographer.doFrame(Choreographer.java:550)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
android android-bitmap
28个回答
449
投票

OutOfMemoryError是android中最常见的问题,尤其是在处理位图时。当由于内存空间不足而无法分配对象时,Java虚拟机(JVM)会抛出此错误,并且垃圾收集器也无法释放一些空间。

正如Aleksey所提到的,您可以在清单文件android:hardwareAccelerated="false"中添加以下实体,android:largeHeap="true"它将适用于某些环境。

<application
    android:allowBackup="true"
    android:hardwareAccelerated="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

你一定要阅读一些Androids Developer的概念,特别是这里:qazxsw poi

阅读所有5个主题并重新编写代码。如果它仍然不起作用,我们将很高兴看到您在教程材料中做错了什么。

这里是SOF中这些类型错误的一些可能答案

Displaying Bitmaps Efficiently

Android: BitmapFactory.decodeStream() out of memory with a 400KB file with 2MB free heap

How to solve java.lang.OutOfMemoryError trouble in Android

Android : java.lang.OutOfMemoryError

java.lang.OutOfMemoryError

编辑:来自@cjnash的评论

对于那些在添加此行后仍然崩溃的人,请尝试将图像粘贴到res / drawable-xhdpi /文件夹而不是res / drawable /,它可能会解决您的问题。


3
投票

解决方案在您的清单文件中尝试此操作并使用Glide Library

编译'com.github.bumptech.glide:glide:3.7.0'

<application
    android:allowBackup="true"
    android:icon="@mipmap/guruji"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:largeHeap="true"
    android:theme="@style/AppTheme">

机器人:硬件加速=“假”

机器人:largeHeap = “真”

    **Use Glide Library and Override size to less size;**

 if (!TextUtils.isEmpty(message.getPicture())) {
            Glide.with(mContext).load(message.getPicture())
                    .thumbnail(0.5f)
                    .crossFade()
                    .transform(new CircleTransform(mContext))
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .into(holder.imgProfile);
        } 

使用此库

<application
    android:allowBackup="true"
    android:hardwareAccelerated="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

它工作愉快的编码

  compile 'com.github.bumptech.glide:glide:3.7.0'   

3
投票

问题:无法分配带有16777120个空闲字节的37748748字节分配和17MB直到OOM

解决方案:1。打开您的清单文件2.在应用程序标记内部添加以下两行

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;


public class CircleTransform extends BitmapTransformation {
    public CircleTransform(Context context) {
        super(context);
    }

    @Override
    protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
        return circleCrop(pool, toTransform);
    }

    private static Bitmap circleCrop(BitmapPool pool, Bitmap source) {
        if (source == null) return null;

        int size = Math.min(source.getWidth(), source.getHeight());
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;

        // TODO this could be acquired from the pool too
        Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);

        Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
        }

        Canvas canvas = new Canvas(result);
        Paint paint = new Paint();
        paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
        paint.setAntiAlias(true);
        float r = size / 2f;
        canvas.drawCircle(r, r, r, paint);
        return result;
    }

    @Override
    public String getId() {
        return getClass().getName();
    }
}

示例:

 android:hardwareAccelerated="false"
 android:largeHeap="true"

2
投票

我也遇到了这个问题。

与上面的大多数人一样。问题是由巨大的图像引起的。

只需调整一些图像大小,无需更改任何代码。


2
投票

在某些情况下(例如循环中的操作)垃圾收集器比您的代码慢。您可以使用 <application android:allowBackup="true" android:hardwareAccelerated="false" android:largeHeap="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> 等待垃圾收集器。


2
投票

我发现'drawable'文件夹中的图像将在高清手机上转换为更大的图像。例如,200k图像将重新采样到更高的分辨率,如800k或32000k。我必须自己发现这个并且到目前为止还没有看到这个堆内存陷阱的文档。为了防止这种情况,我将所有内容放在drawable-nodpi文件夹中(除了在BitmapFactory中使用基于特定设备堆的'options')。我不能让我的应用程序的大小膨胀与多个可绘制的文件夹,特别是因为屏幕defs的范围现在是如此巨大。棘手的是工作室现在没有在项目视图中专门指出'drawable-nodpi'文件夹,它只显示一个'drawable'文件夹。如果你不小心,当你将图像放到工作室中的这个文件夹时,它实际上不会被放入drawable-nodpi:

helper method from this answer

Careful here 'backgroundtest' did not actually go to drawable-nodpi and will be resampled higher, such as 4x or 16x of the original dimensions for high def screens.

请务必单击对话框中的nodpi文件夹,因为项目视图不会像以前那样单独显示所有可绘制文件夹,因此不会立即显示它出错了。在我很久以前删除它后,Studio在某些时候重新创建了香草'drawable':

enter image description here


1
投票

我是Android开发中的新手,但我希望我的解决方案有所帮助,它完全符合我的条件。我使用Imageview并将其背景设置为“src”因为我试图制作一个帧动画。我得到了同样的错误但是当我尝试编码时它起作用了

enter image description here

1
投票

当我在进行新活动时没有杀死我的旧活动时,我遇到了这个问题。我用int ImageID = this.Resources.GetIdentifier(questionPlay[index].Image.ToLower(), "anim", PackageName); imgView.SetImageResource(ImageID); AnimationDrawable animation = (AnimationDrawable)imgView.Drawable; animation.Start(); animation.Dispose(); 修好了

finish();

1
投票

这对我有用:只需将图像从drawable文件夹移动到drawable-hdpi。


1
投票
    Intent goToMain = new Intent(this,MainActivity.class);
    startActivity(goToMain);
    finish();

50/100如果使用100则原始分辨率可以停止应用程序内存不足。

如果50或小于100这将是50%或小于100分辨率,所以这将防止内存不足问题


1
投票

您必须在drawable中更改对象的大小。这对于安卓来说太大了。例如如果要设置图像,请尝试使用较少像素的图像。这个对我有用。谢谢。 :)


79
投票

您是否尝试将此添加到应用程序下的清单中? Solution for OutOfMemoryError: bitmap size exceeds VM budget

像这样

android:largeHeap="true"

1
投票

您的应用程序崩溃,因为您的图像大小(以MB或KB为单位)太大,因此没有为此分配空间。所以在将图像粘贴到drawable之前只需减小尺寸。

要么

您可以在Manifest.xml中的应用程序标记中添加以下内容

Bitmap image =((BitmapDrawable)imageView1.getDrawable()).getBitmap();

ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();

image.compress(Bitmap.CompressFormat.JPEG,50/100,byteArrayOutputStream);

添加此应用程序后不会崩溃。

  • 总是在App中使用较小尺寸的图像。
  • 如果您在应用中添加大尺寸图像,则应添加上述syntex,但应用程序大小会增加。

1
投票

添加后我的问题解决了

 android:hardwareAccelerated="false"
    android:largeHeap="true"
    android:allowBackup="true"

在Build.Gradle文件中


1
投票

将此添加到应用程序下的清单中?机器人:largeHeap = “真”


0
投票

如果上传图像,请尝试降低图像质量,这是位图的第二个参数。这是我案例中的解决方案。以前它是90,然后我尝试60(现在在下面的代码中)。

 dexOptions {
        incremental true
        javaMaxHeapSize "4g"
        preDexLibraries true
        dexInProcess = true
    }

0
投票

尝试最简单的一个。也许您的应用程序崩溃了,因为您的图像大小(以MB为单位)太大,因此没有为此分配空间。因此,在将图像粘贴到drawable中之前,只需缩小任何查看器软件的大小,或者如果您在运行时从图库中获取图像,则比保存之前压缩您的位图。它对我有用。绝对适合你。


0
投票
Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
finalBitmap.compress(Bitmap.CompressFormat.JPEG,60,baos);
byte[] b = baos.toByteArray();

然后在Application标签中,添加大堆size =“true


0
投票
stream = activity.getContentResolver().openInputStream(uri);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;

bitmap = BitmapFactory.decodeStream(stream, null, options);
int Height = bitmap.getHeight();
int Width = bitmap.getWidth();
enter code here
int newHeight = 1000;
float scaleFactor = ((float) newHeight) / Height;
float newWidth = Width * scaleFactor;

float scaleWidth = scaleFactor;
float scaleHeight = scaleFactor;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
resizedBitmap= Bitmap.createBitmap(bitmap, 0, 0,Width, Height, matrix, true);
bitmap.recycle();

0
投票

使用像Last but not the least.... Try Method One: Simple Add these lines of code in the gradle file dexOptions { incremental true javaMaxHeapSize "4g" } Example: android { compileSdkVersion XX buildToolsVersion "28.X.X" defaultConfig { applicationId "com.example.xxxxx" minSdkVersion 14 targetSdkVersion 19 } dexOptions { incremental true javaMaxHeapSize "4g" } } ******************************************************************* Method Two: Add these two lines of code in manifest file... android:hardwareAccelerated="false" android:largeHeap="true" Example: <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:hardwareAccelerated="false" android:largeHeap="true" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> It will Work for sure any of these cases..... Picasso这样的图像加载库。使用这些库可以防止将来崩溃。


0
投票

我想你想把这个图像用作图标。正如Android告诉你的那样,你的形象太大了。您只需要缩放图像,以便Android知道要使用的图像大小以及何时根据屏幕分辨率。要在Android Studio中完成此操作:1。右键单击res文件夹,2。选择图像资源3.选择图标类型4.为图标命名5.在资产类型上选择图像6.修剪图像单击下一步并完成。在您的xml或源代码中,只需根据所选的资产类型引用现在位于布局或mipmap文件夹中的图像。错误将消失。


25
投票

实际上你可以在你的清单中添加这些行 <application android:name=".ParaseApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" android:largeHeap="true" > android:hardwareAccelerated="false"它适用于某些情况,但要注意代码的其他部分可以与此争论。

android:largeHeap="true"

20
投票

对我来说,问题是我的.png文件被解压缩为内存中非常大的位图,因为图像具有非常大的尺寸(即使文件大小很小)。

所以修复就是简单地调整图像大小:)


20
投票

这应该工作

<application
    android:allowBackup="true"
    android:hardwareAccelerated="false"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

9
投票

使用Glide Library和Override尺寸减小尺寸;

 BitmapFactory.Options options = new BitmapFactory.Options();
 options.inSampleSize = 8;

 mBitmapSampled = BitmapFactory.decodeFile(mCurrentPhotoPath,options);

9
投票

在设置为ImageView之前调整图像大小,如下所示:

Glide.with(mContext).load(imgID).asBitmap().override(1080, 600).into(mImageView);

其中size是ImageView的实际大小。您可以通过测量来达到尺寸:

Bitmap.createScaledBitmap(_yourImageBitmap, _size, _size, false);

并使用下一个尺寸imageView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); imageView.getMeasuredWidth()imageView.getMeasuredHeight()


4
投票

我通过调整图像大小来解决这个问题。我使用的是xamarin形式。减小PNG图像的大小解决了问题。


3
投票

我得到了以下错误

“E / art:Throwing OutOfMemoryError”无法分配47251468字节分配16777120个空闲字节和23MB直到OOM“

在AndroidManifest.xml中添加scaling后,我摆脱了所有错误

android:largeHeap="true"
© www.soinside.com 2019 - 2024. All rights reserved.