ヒープ サイズを動的に増やすことはできませんが、使用することでさらに使用するように要求できます。
アンドロイド:ラージヒープ="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 ピクセルの画像が最終的にImageView
.
デコーダーにイメージをサブサンプリングするように指示するには、より小さいバージョンをメモリにロードし、オブジェクトで に設定inSampleSize
しtrue
ますBitmapFactory.Options
。たとえば、解像度 2100 x 1500 ピクセルのイメージをinSampleSize
4 でデコードすると、約 512x384 のビットマップが生成されます。これをメモリにロードすると、イメージ全体で 12MB ではなく 0.75MB が使用されます (ビットマップ構成が の場合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;
}
注inSampleSize
: 2 のべき乗の値が計算されます。これは、ドキュメントに従って、最も近い 2 のべき乗に切り捨てて、デコーダが最終的な値を使用するため
です。
この方法を使用するには、最初に に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) を促すと便利な場合がよくあります。これは、特に GC_FOR_ALLOC タイプの発生を防止するため、または断片化を減らすためにガベージ コレクションを呼び出す場合、ART ではそれほど必要ではありません。System.getProperty("java.vm.version") を呼び出して、どのランタイムが使用されているかを確認できます。ART を使用している場合、プロパティの値は「2.0.0」以上です。
さらに、Android オープンソース プロジェクト (AOSP) では、メモリ管理を改善するための圧縮ガベージ コレクターが開発中です。このため、GC の圧縮と互換性のない手法 (オブジェクト インスタンス データへのポインターの保存など) の使用は避ける必要があります。これは、Java Native Interface (JNI) を利用するアプリにとって特に重要です。詳細については、JNI の問題の防止を参照してください。
JNI の問題の防止
ART の JNI は、Dalvik のものよりもいくらか厳密です。一般的な問題を検出するには、CheckJNI モードを使用することをお勧めします。アプリで C/C++ コードを使用する場合は、次の記事を確認する必要があります。
また、ネイティブ メモリ ( NDK & JNI ) を使用できるため、実際にはヒープ サイズの制限を回避できます。
これについていくつかの投稿があります:
そして、これがそのために作られたライブラリです: