Android:java.lang.OutOfMemoryError:无法分配23970828字节分配与2097152可用字节和2MB直到OOM


355

我想从已存储的SD卡中的ImageView中显示位图图像。运行后,我的应用程序崩溃并且出现OutOfMemoryError错误:

(java.lang.OutOfMemoryError:未能分配23970828字节分配和2097152可用字节,以及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)

4
检查图像的像素,宽度不得超过1440,高度不得超过2560,这样就不会显示OutOfMemoryError
Pankaj Lilan

1
@PankajLilan在哪里找到这些值(1440 X 2560)?android文档有参考吗?
LCJ

Answers:


525

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

您一定要阅读一些Android Developers概念,特别是在这里:有效显示位图

阅读所有5个主题,然后再次重写代码。如果仍然无法正常工作,我们将很高兴看到您在本教程资料中做错了什么。

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

Android:BitmapFactory.decodeStream()内存不足,带有400KB文件和2MB可用堆

如何解决Android中的java.lang.OutOfMemoryError问题

Android:java.lang.OutOfMemoryError

java.lang.OutOfMemoryError

OutOfMemoryError的解决方案:位图大小超出VM预算

编辑:从@cjnash的评论

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


1
请问您如何最终解决该问题?因为我有同样的问题...实际上,您可以在清单中添加以下行android:hardwareAccelerated =“ false”,android:largeHeap =“ true”在某些情况下可以正常工作,但请注意,代码的另一部分可以正在为此争论...
Aleksey Timoshchenko '16

6
添加此功能后,应用导航变得非常缓慢。
Uma Achanta '16

10
android:hardwareAccelerated =“ false”冻结您的应用程序
Rahim Rahimov

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

6
您为什么建议android:hardwareAccelerated =“ false?它有什么好处?
batmaci

86

您是否尝试过将其添加到应用程序下的清单中? 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" >

17
我已经尝试过使用此android:largeHeap =“ true”但收到相同的错误
androidTag

1
请尝试先压缩图像,然后才能使用此链接进行操作tinyjpg.com
TSG

1
您也可以使用此网站压缩png
TSG 2015年

27

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

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


3
这是正确的解决方案,因为我首先尝试了上述解决方案,但是应用后android:hardwareAccelerated="false",诸如布局阴影之类的某些动画无法正常工作。但是调整大小后,所有问题都解决了,谢谢!为此提示+1!
Kaushal28年

1
这解决了我的问题。谢谢@petrus
红阮

27

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

2
不起作用,当使用Bitmap.createBitmap时,它以相同的错误崩溃了
Narendra Singh

@King对不起(我也花了一些时间来解决这个问题,对我来说这是工作。但这只是其中一种方式...有很多不同的方法
Aleksey Timoshchenko

2
android:hardwareAccelerated =“ false”的目的是什么?
IgorGanapolsky

@IgorGanapolsky来自官方文件的说法.. 请参阅此链接
Shylendra Madda


11

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

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

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

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

并使用下一大小imageView.getMeasuredWidth()imageView.getMeasuredHeight()scaling


我已经尝试过使用此android:largeHeap =“ true”但收到相同的错误
androidTag

为什么这样的方法不一定奏效的另一个示例(使用私有应用程序存储):将位图放置在res / drawable /中会产生相同的错误,但不会每次都发生。将相同的位图放入res / drawable-xhdpi /将不再具有该错误。因此,作为答案,它本身是不正确的。
CmosBattery

8

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

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

6

我低于错误

“ E / art:抛出OutOfMemoryError”无法分配47251468字节分配,其中包含16777120可用字节和23MB,直到OOM为止。

加入后,android:largeHeap="true"AndroidManifest.xml中然后我摆脱所有的错误

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

4

我已通过将图像调整为较小的尺寸来解决此问题。我正在使用xamarin形式。减小PNG图像的大小可以解决该问题。


4

问题:未能分配37748748字节分配,其中16777120个空闲字节和17MB直到OOM

解决方案:1.打开清单文件2.在应用程序标签内只需在两行以下添加

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

4

我发现“可绘制”文件夹中的图像将在高清手机上转换为更大的图像。例如,一个200k的图像将被重新采样到更高的分辨率,例如800k或32000k。我不得不自己发现它,到目前为止,还没有看到有关此堆内存陷阱的文档。为了防止这种情况,我将所有内容都放在了drawable-nodpi文件夹中(除了根据特定的设备堆在BitmapFactory中使用“选项”之外)。我负担不起拥有多个可绘制文件夹的应用程序大小,尤其是现在屏幕定义的范围如此之大。棘手的是,Studio现在并未在项目视图中专门指出“ drawable-nodpi”文件夹,而只是显示了“ drawable”文件夹。如果您不小心,将图像放到studio中的该文件夹中时,它将不会

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之后,Studio便为我重新创建了香草“ drawable”:

在此处输入图片说明



3

解决方案在清单文件中尝试使用Glide库

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


2

我也有问题。

与上述大多数其他工具相同。问题是由巨大的图像引起的。

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



1

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

1

当我继续进行新活动时没有杀死旧活动时,我遇到了这个问题。我用finish();

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

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

ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();

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

如果50/100(如果使用100),则原始分辨率可能会导致Apps内存不足。

如果50或小于100,则为50%或小于100的分辨率,这样可以防止出现内存不足的问题



1

您的应用程序崩溃是因为您的图片大小(以MB或KB为单位)太大,因此没有为此分配空间。因此,在将图像粘贴到drawable中之前,请先减小其大小。

要么

您可以在Manifest.xml的应用程序标记中添加“跟随”

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

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

  • 在App中始终使用较小尺寸的图像。
  • 如果您在app中添加了大尺寸的图像,则应添加以上syntex,但是App大小会增加。

1

添加后我的问题解决了

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

在Build.Gradle文件中


这只会使您的应用程序的内存使用量真正膨胀
OneCricketeer

@ cricket_007的后果是什么?
Sreekanth Karumanaghat

1
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.....

0

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

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

0

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


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

然后在Appliaction标记中,添加largeheapsize =“ true


0

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


0

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

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.