您不能动态增加堆大小,但可以通过使用来请求使用更多。
android:largeHeap =“ true”
在中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像素的图像最终显示在的128x128像素的缩略图中,则不值得将其加载到内存中ImageView
。
为了告诉解码器对图像进行二次采样,将较小的版本加载到内存中,inSampleSize
并true
在您的BitmapFactory.Options
对象中将其设置为。例如,以2解码的分辨率为2100 x 1500像素的图像inSampleSize
会生成大约512x384的位图。将其加载到内存中需要使用0.75MB而不是12MB的完整图像(假设的位图配置ARGB_8888
)。这是一种根据目标宽度和高度计算样本大小值(是2的幂)的方法:
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
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;
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
注意:根据inSampleSize
文档,解码器使用四舍五入到最接近的2的幂的最终值来计算2的幂
。
要使用此方法,请先将inJustDecodeBounds
设置为true
,然后将选项传递给解码,然后再使用新inSampleSize
值inJustDecodeBounds
设置为再次解码false
:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
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;
in = mContentResolver.openInputStream(uri);
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--;
o = new BitmapFactory.Options();
o.inSampleSize = scale;
bitmap = BitmapFactory.decodeStream(in, null, o);
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"
Google的摘录对此进行解释不是一个好主意,
但是,请求大堆的能力仅适用于少数可以证明需要消耗更多RAM的应用程序(例如大型照片编辑应用程序)。切勿仅仅因为内存用完并且需要快速修复而请求大堆-仅在确切知道所有内存的分配位置以及为什么必须保留它时,才应使用它。但是,即使您确信自己的应用程序可以证明大堆的合理性,也应尽可能避免请求它。使用额外的内存将越来越不利于整体用户体验,因为在任务切换或执行其他常见操作时,垃圾回收将花费更长的时间并且系统性能可能会降低。
经过艰苦的工作,out of memory errors
我会说将其添加到清单中以避免oom问题不是罪恶
在Android Runtime(ART)上验证应用行为
对于运行Android 5.0(API级别21)及更高版本的设备,Android运行时(ART)是默认运行时。该运行时提供了许多功能,可改善Android平台和应用的性能和流畅性。您可以在“简介”中找到有关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的JNI更为严格。使用CheckJNI模式来捕获常见问题是一个特别好的主意。如果您的应用程序使用C / C ++代码,则应阅读以下文章:
另外,您可以使用本机内存(NDK和JNI),因此实际上可以绕过堆大小限制。
这是一些有关它的文章:
这是为此而建的图书馆: