您不能动态增加堆大小,但您可以通过 using 请求使用更多。
机器人:大堆=“真”
在中manifest.xml
,您可以在清单中添加这些行,它适用于某些情况。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
是否应使用大型 Dalvik 堆创建应用程序的进程。这适用于为应用程序创建的所有进程。它仅适用于加载到进程中的第一个应用程序;如果您使用共享用户 ID 来允许多个应用程序使用一个进程,则它们都必须一致地使用此选项,否则它们将产生不可预知的结果。大多数应用程序不应该需要这个,而是应该专注于减少它们的整体内存使用以提高性能。启用此功能也不能保证可用内存的固定增加,因为某些设备受到其总可用内存的限制。
要在运行时查询可用内存大小,请使用方法getMemoryClass()
或getLargeMemoryClass()
。
如果仍然面临问题,那么这也应该有效
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
mBitmapInsurance = BitmapFactory.decodeFile(mCurrentPhotoPath,options);
如果设置为大于 1 的值,则请求解码器对原始图像进行二次采样,返回较小的图像以节省内存。
这是 BitmapFactory.Options.inSampleSize 在显示图像速度方面的最佳使用。文档提到使用 2 的幂的值,所以我正在使用 2、4、8、16 等。
让我们更深入地了解图像采样:
例如,如果 1024x768 像素的图像最终会以ImageView
.
告诉解码器对图像进行二次采样,将较小的版本加载到内存中,在您的对象中设置inSampleSize
为。例如,分辨率为 2100 x 1500 像素的图像使用4 进行解码会生成大约 512x384 的位图。将其加载到内存中使用 0.75MB 而不是 12MB 的完整图像(假设位图配置为)。这是一种根据目标宽度和高度计算样本大小值的方法,该值是 2 的幂:true
BitmapFactory.Options
inSampleSize
ARGB_8888
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;
}
注意:根据
inSampleSize
文档,计算二值的幂是因为解码器通过向下舍入到最接近的二的幂来使用最终值。
要使用此方法,首先使用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;
}
如何管理应用程序的内存:链接
android:largeHeap="true"
在这里使用谷歌的摘录来解释它 不是一个好主意,
但是,请求大堆的能力仅适用于一小部分可以证明需要消耗更多 RAM 的应用程序(例如大型照片编辑应用程序)。永远不要仅仅因为你的内存已经用完并且需要快速修复就请求一个大堆——只有在你知道所有内存被分配到哪里以及为什么必须保留它时才应该使用它。然而,即使您确信您的应用程序可以证明大堆是合理的,您也应该尽可能避免请求它。使用额外的内存将越来越多地损害整体用户体验,因为垃圾收集将花费更长的时间,并且在任务切换或执行其他常见操作时系统性能可能会变慢。
在与我一起努力工作之后,out of memory errors
我会说将其添加到清单中以避免 oom 问题不是一种罪过
在 Android 运行时 (ART) 上验证应用行为
Android 运行时 (ART) 是运行 Android 5.0(API 级别 21)及更高版本的设备的默认运行时。此运行时提供了许多可提高 Android 平台和应用程序的性能和流畅性的功能。您可以在介绍 ART中找到有关 ART 新功能的更多信息。
然而,一些适用于 Dalvik 的技术不适用于 ART。本文档让您了解在迁移现有应用程序以与 ART 兼容时需要注意的事项。大多数应用程序在使用 ART 运行时应该可以正常工作。
解决垃圾收集 (GC) 问题
在 Dalvik 下,应用程序经常发现显式调用 System.gc() 以提示垃圾回收 (GC) 很有用。这对于 ART 来说应该没那么必要了,尤其是当您调用垃圾收集来防止 GC_FOR_ALLOC 类型的出现或减少碎片时。您可以通过调用 System.getProperty("java.vm.version") 来验证正在使用的运行时。如果使用 ART,则属性值为“2.0.0”或更高。
此外,Android 开源项目 (AOSP) 中正在开发压缩垃圾收集器,以改进内存管理。因此,您应该避免使用与压缩 GC 不兼容的技术(例如保存指向对象实例数据的指针)。这对于使用 Java 本机接口 (JNI) 的应用程序尤其重要。有关更多信息,请参阅防止 JNI 问题。
防止 JNI 问题
ART 的 JNI 比 Dalvik 的要严格一些。使用 CheckJNI 模式来捕获常见问题是一个特别好的主意。如果您的应用使用 C/C++ 代码,您应该查看以下文章:
此外,您可以使用本机内存(NDK和JNI),因此您实际上绕过了堆大小限制。
以下是一些关于它的帖子:
这是为它制作的图书馆: