gpt4 book ai didi

android - 如何解决Android中的java.lang.OutOfMemoryError故障

转载 作者:IT老高 更新时间:2023-10-28 13:17:54 25 4
gpt4 key购买 nike

尽管我在 drawable 文件夹中有非常小的图像,但我从用户那里收到了这个错误。而且我没有在代码中使用任何位图函数。至少是故意的:)

java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:683)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:513)
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:889)
at android.content.res.Resources.loadDrawable(Resources.java:3436)
at android.content.res.Resources.getDrawable(Resources.java:1909)
at android.view.View.setBackgroundResource(View.java:16251)
at com.autkusoytas.bilbakalim.SoruEkrani.cevapSecimi(SoruEkrani.java:666)
at com.autkusoytas.bilbakalim.SoruEkrani$9$1.run(SoruEkrani.java:862)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5602)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(Native Method)

根据这个stackTrace,我在这一行出现了这个错误('tv'是一个textView):
tv.setBackgroundResource(R.drawable.yanlis);

有什么问题?如果您需要有关代码的其他信息,我可以添加它。
谢谢!

最佳答案

您不能动态增加堆大小,但可以通过 using 请求使用更多。

android:largeHeap="true"



manifest.xml ,您可以在 list 中添加这些行,它适用于某些情况。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">

Whether your application's processes should be created with a large Dalvik heap. This applies to all processes created for the application. It only applies to the first application loaded into a process; if you're using a shared user ID to allow multiple applications to use a process, they all must use this option consistently or they will have unpredictable results. Most apps should not need this and should instead focus on reducing their overall memory usage for improved performance. Enabling this also does not guarantee a fixed increase in available memory, because some devices are constrained by their total available memory.



要在运行时查询可用内存大小,请使用方法 getMemoryClass()getLargeMemoryClass() .

如果仍然面临问题,那么这也应该有效
 BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
mBitmapInsurance = BitmapFactory.decodeFile(mCurrentPhotoPath,options);

If set to a value > 1, requests the decoder to subsample the original image, returning a smaller image to save memory.

这是 BitmapFactory.Options.inSampleSize 在显示图像速度方面的最佳使用。
文档提到使用 2 的幂的值,所以我正在使用 2、4、8、16 等。

让我们更深入地了解图像采样:

例如,如果它最终会显示在 ImageView 中的 128x128 像素缩略图中,那么将 1024x768 像素的图像加载到内存中是不值得的。 .

要告诉解码器对图像进行二次采样,将较小的版本加载到内存中,请设置 inSampleSizetrue在您的 BitmapFactory.Options对象。例如,分辨率为 2100 x 1500 像素的图像使用 inSampleSize 解码。 4 产生一个大约 512x384 的位图。将其加载到内存中使用 0.75MB 而不是完整图像的 12MB(假设位图配置为 ARGB_8888)。这是一种基于目标宽度和高度计算样本大小值的方法,该值是 2 的幂:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

final int halfHeight = height / 2;
final int halfWidth = width / 2;

// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}

return inSampleSize;
}

Note: A power of two value is calculated because the decoder uses a final value by rounding down to the nearest power of two, as per the inSampleSize documentation.



要使用此方法,首先使用 inJustDecodeBounds 解码设置为 true ,传递选项,然后使用新的 inSampleSize 再次解码值和 inJustDecodeBounds设置为 false :
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}

这种方法可以很容易地将任意大尺寸的位图加载到 ImageView 中。显示一个 100x100 像素的缩略图,如以下示例代码所示:
mImageView.setImageBitmap(decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

您可以按照类似的过程,通过替换适当的 BitmapFactory.decode* 来解码来自其他来源的位图。需要的方法。

我发现这段代码也很有趣:
private Bitmap getBitmap(String path) {

Uri uri = getImageUri(path);
InputStream in = null;
try {
final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
in = mContentResolver.openInputStream(uri);

// Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(in, null, o);
in.close();

int scale = 1;
while ((o.outWidth * o.outHeight) * (1 / Math.pow(scale, 2)) >
IMAGE_MAX_SIZE) {
scale++;
}
Log.d(TAG, "scale = " + scale + ", orig-width: " + o.outWidth + ",
orig-height: " + o.outHeight);

Bitmap bitmap = null;
in = mContentResolver.openInputStream(uri);
if (scale > 1) {
scale--;
// scale to max possible inSampleSize that still yields an image
// larger than target
o = new BitmapFactory.Options();
o.inSampleSize = scale;
bitmap = BitmapFactory.decodeStream(in, null, o);

// resize to desired dimensions
int height = bitmap.getHeight();
int width = bitmap.getWidth();
Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
height: " + height);

double y = Math.sqrt(IMAGE_MAX_SIZE
/ (((double) width) / height));
double x = (y / height) * width;

Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, (int) x,
(int) y, true);
bitmap.recycle();
bitmap = scaledBitmap;

System.gc();
} else {
bitmap = BitmapFactory.decodeStream(in);
}
in.close();

Log.d(TAG, "bitmap size - width: " +bitmap.getWidth() + ", height: " +
bitmap.getHeight());
return bitmap;
} catch (IOException e) {
Log.e(TAG, e.getMessage(),e);
return null;
}

如何管理应用程序的内存: link

使用 android:largeHeap="true" 不是一个好主意这是解释它的谷歌摘录,

However, the ability to request a large heap is intended only for a small set of apps that can justify the need to consume more RAM (such as a large photo editing app). Never request a large heap simply because you've run out of memory and you need a quick fix—you should use it only when you know exactly where all your memory is being allocated and why it must be retained. Yet, even when you're confident your app can justify the large heap, you should avoid requesting it to whatever extent possible. Using the extra memory will increasingly be to the detriment of the overall user experience because garbage collection will take longer and system performance may be slower when task switching or performing other common operations.



在与 out of memory errors 一起苦苦工作后我会说将这个添加到 list 中以避免 oom 问题并不是一种罪过

在 Android 运行时 (ART) 上验证应用行为

Android 运行时 (ART) 是运行 Android 5.0(API 级别 21)及更高版本的设备的默认运行时。此运行时提供了许多可提高 Android 平台和应用程序的性能和流畅度的功能。您可以在 Introducing ART 中找到有关 ART 新功能的更多信息。 .

但是,一些适用于 Dalvik 的技术不适用于 ART。本文档让您了解在迁移现有应用程序以与 ART 兼容时需要注意的事项。大多数应用程序在与 ART 一起运行时应该可以正常工作。

解决垃圾收集 (GC) 问题

在 Dalvik 下,应用程序经常发现显式调用 System.gc() 来提示垃圾回收 (GC) 很有用。对于 ART,这应该是不必要的,特别是如果您正在调用垃圾收集以防止 GC_FOR_ALLOC 类型的发生或减少 fragment 。您可以通过调用 System.getProperty("java.vm.version") 来验证正在使用哪个运行时。如果正在使用 ART,则该属性的值为“2.0.0”或更高。

此外,Android 开源项目 (AOSP) 正在开发压缩垃圾收集器,以改进内存管理。因此,您应该避免使用与压缩 GC 不兼容的技术(例如保存指向对象实例数据的指针)。这对于使用 Java native 接口(interface) (JNI) 的应用程序尤其重要。有关更多信息,请参阅防止 JNI 问题。

防止 JNI 问题

ART 的 JNI 比 Dalvik 的要严格一些。使用 CheckJNI 模式来捕获常见问题是一个特别好的主意。如果您的应用程序使用 C/C++ 代码,您应该查看以下文章:

此外,您可以使用 native 内存( NDKJNI ),因此您实际上可以绕过堆大小限制。

以下是一些关于它的帖子:
  • How to cache bitmaps into native memory
  • https://stackoverflow.com/a/9428660/1761003
  • JNI bitmap operations , for helping to avoid OOM when using large images

  • 这是一个为它制作的图书馆:
  • https://github.com/AndroidDeveloperLB/AndroidJniBitmapOperations
  • 关于android - 如何解决Android中的java.lang.OutOfMemoryError故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25719620/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com