Android:java.lang.OutOfMemoryError: Failed to allocate a 23970828 byte allocation with 2097152 free bytes and 2MB until OOM

Android:java.lang.OutOfMemoryError: Failed to allocate a 23970828 byte allocation with 2097152 free bytes and 2MB until OOM

我想在 ImageView 中显示已存储的 sd 卡中的 Bitmap 图像。在 运行 之后,我的应用程序崩溃并出现 OutOfMemoryError 错误:

(java.lang.OutOfMemoryError: Failed to allocate a 23970828 byte allocation with 2097152 free bytes and 2MB until 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:largeHeap="true"?

像这样

  <application
      android:name=".ParaseApplication"
      android:allowBackup="true"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:theme="@style/AppTheme"
      android:largeHeap="true" >

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

如 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">

您绝对应该阅读一些 Android 开发人员概念,尤其是此处:Displaying Bitmaps Efficiently

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

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

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

Solution for OutOfMemoryError: bitmap size exceeds VM budget

编辑:来自@cjnash

的评论

对于添加此行后仍然崩溃的任何人,请尝试将您的图像粘贴到您的 res/drawable-xhdpi/ 文件夹而不是您的 res/drawable/ ,这应该可以解决此问题

在设置为 ImageView 之前调整你的图像:

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

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

imageView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));

并使用下一个尺寸 imageView.getMeasuredWidth()imageView.getMeasuredHeight() 用于 scaling

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

所以解决方法是简单地调整图像大小:)

使用Glide Library并将大小覆盖为更小的大小;

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

实际上,您可以在清单中添加这些行 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">

我已经通过将图像尺寸缩小来解决了这个问题。我正在使用 xamarin 形式。减小 PNG 图像的大小解决了问题。

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

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

这应该有效

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

 mBitmapSampled = BitmapFactory.decodeFile(mCurrentPhotoPath,options);

我遇到了以下错误

"E/art: Throwing OutOfMemoryError "Failed to allocate a 47251468 byte allocation with 16777120 free bytes and 23MB until OOM"

AndroidManifest.xml 中添加 android:largeHeap="true" 之后,我消除了所有错误

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

我是 android 开发中的新手,但我希望我的解决方案有所帮助,它非常适合我的情况。我正在使用 Imageview 并将其背景设置为 "src" 因为我正在尝试制作帧动画。我遇到了同样的错误,但是当我尝试对此进行编码时它起作用了

int ImageID = this.Resources.GetIdentifier(questionPlay[index].Image.ToLower(), "anim", PackageName);
            imgView.SetImageResource(ImageID);
            AnimationDrawable animation = (AnimationDrawable)imgView.Drawable;
            animation.Start();
            animation.Dispose();

我也有这个问题。

与上面的大多数其他人相同。 图片过大导致的问题

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

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

ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();

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

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

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

试试最简单的。也许您的应用程序崩溃是因为您的图像大小(以 MB 为单位)太大,因此它没有为此分配 space。因此,在将图像粘贴到可绘制对象之前,只需通过任何查看器软件减小尺寸,或者如果您在 运行 时间从图库中获取图像,那么在保存之前压缩您的位图。 它对我有用。绝对适合你。

在某些情况下(例如循环中的操作)垃圾收集器比您的代码慢。您可以使用 helper method from this answer 等待垃圾收集器

我 运行 在转向新的 activity 时没有杀死旧的 activity 时遇到了这个问题。我用 finish();

修复了它
    Intent goToMain = new Intent(this,MainActivity.class);
    startActivity(goToMain);
    finish();

解决方案在您的清单文件中尝试这个并使用 Glide Library

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

    **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);
        } 

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">

使用这个库

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

它的工作快乐编码

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();
    }
}

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

Issue : Failed to allocate a 37748748 byte allocation with 16777120 free bytes and 17MB until OOM

解决方案: 1.open 你的清单文件 2. 在application tag里面添加下面两行

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

示例:

 <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">

我发现 'drawable' 文件夹中的图像会在高清手机上转换为更大的图像。例如,200k 的图像将被重新采样为更高分辨率,如 800k 或 32000k。我不得不自己发现这一点,到目前为止还没有看到关于这个堆内存陷阱的文档。为了防止这种情况,我将所有内容都放在 drawable-nodpi 文件夹中(除了根据特定设备堆在 BitmapFactory 中使用 'options' 之外)。我不能让我的应用程序因多个可绘制文件夹而变得臃肿,尤其是现在屏幕定义的范围如此之大。棘手的是,studio 现在并没有在项目视图中具体指明 'drawable-nodpi' 文件夹,它只显示一个 'drawable' 文件夹。如果你不小心,当你在工作室中将图像拖放到这个文件夹时,它实际上不会被拖放到 drawable-nodpi:

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':

您必须更改可绘制对象的大小。它太大 android 无法显示。例如如果您正在设置图像,请尝试使用较少像素的图像。这个对我有用。 谢谢。 :)

您的应用程序崩溃是因为您的图像大小(以 MB 或 KB 为单位)太大,因此它没有为此分配 space。因此,在将图像粘贴到可绘制对象之前,只需减小尺寸即可。

您可以在 Manifest.xml

的应用程序标签中添加关注
 android:hardwareAccelerated="false"
    android:largeHeap="true"
    android:allowBackup="true"

添加本应用后不会崩溃

  • 始终在应用程序中使用较小尺寸的图像。
  • 如果你在应用中添加大尺寸图片,你应该添加上面的语法,但应用大小会增加。

添加后我的问题解决了

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

在 Build.Gradle 文件中

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();

然后在Application标签中,添加large heap size="true

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 or Glide 这样的图像加载库。使用这些库将防止将来发生崩溃。

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

将此添加到应用程序下的清单中? android:largeHeap="true"

我真的不建议像这样编辑清单

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

这些选项会导致您的应用的动画效果不流畅。此外 'liveData' 或更改您的本地数据库(Sqlite,Room)激活缓慢。不利于用户体验。

所以我推荐RESIZE位图

下面是示例代码

fun resizeBitmap(source: Bitmap): Bitmap {
      val maxResolution = 1000    //edit 'maxResolution' to fit your need
      val width = source.width
      val height = source.height
      var newWidth = width
      var newHeight = height
      val rate: Float

            if (width > height) {
                if (maxResolution < width) {
                    rate = maxResolution / width.toFloat()
                    newHeight = (height * rate).toInt()
                    newWidth = maxResolution
                }
            } else {
                if (maxResolution < height) {
                    rate = maxResolution / height.toFloat()
                    newWidth = (width * rate).toInt()
                    newHeight = maxResolution
                }
            }
            return Bitmap.createScaledBitmap(source, newWidth, newHeight, true)
 }

如果 android:largeHeap="true" 不适合你,那么

1:

Image Compression. I am using this website

2:

Convert images to mdpi,hdpi, xhdpi, xxhdpi, xxxhdpi. I am using this webiste

不要删除 android:largeHeap="true"!

使 android:hardwareAccelerated="false" 变得 activity 具体。希望这可以解决冻结问题和动画问题。像这样...

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:largeHeap="true">
.
.
.
.
<activity android:name=".NavigationItemsFolder.GridsMenuActivityClasses.WebsiteActivity"
            android:windowSoftInputMode="adjustPan"
            android:hardwareAccelerated="false"/>
</application>