回答:
「使用可能なアプリケーションヒープサイズ」というフレーズについては、次の2つの方法で考えることができます。
ハードエラーがトリガーされる前に、アプリはどのくらいのヒープを使用できますか?そして
Android OSのバージョンとユーザーのデバイスのハードウェアの制約を考慮すると、アプリはどのくらいのヒープを使用する必要がありますか?
上記のそれぞれを決定するための異なる方法があります。
上記の項目1の場合: maxMemory()
これはonCreate()
、次のように(たとえば、メインアクティビティのメソッドで)呼び出すことができます。
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.v("onCreate", "maxMemory:" + Long.toString(maxMemory));
このメソッドは、アプリが使用できるヒープの合計バイト数を通知します。
上記の項目2の場合: getMemoryClass()
これは次のように呼び出すことができます。
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
int memoryClass = am.getMemoryClass();
Log.v("onCreate", "memoryClass:" + Integer.toString(memoryClass));
このメソッドは、現在のデバイスの制限を適切に尊重したい場合や、他のアプリが/ サイクルに繰り返し強制されることなく実行する権利を失礼なものとして適切に尊重したい場合に、アプリが使用する必要があるヒープのおよそのメガバイト数を示しますelephantineアプリがAndroidジャグジーで入浴している間、メモリがフラッシュされます。onStop()
onResume()
私が知る限り、この区別は明確に文書化されていませんが、この仮説を5つの異なるAndroidデバイスでテストし(下記を参照)、これが正しい解釈であることを自分の満足度で確認しました。
Androidのストックバージョンの場合、maxMemory()
通常はに示されているのとほぼ同じメガバイト数getMemoryClass()
(つまり、後者の値の約100万倍)を返します。
2つの方法が分岐する可能性がある唯一の状況(私が知っている)は、CyanogenModなどのAndroidバージョンを実行しているルート化されたデバイス上にあります。これにより、ユーザーは各アプリに許可するヒープサイズの大きさを手動で選択できます。たとえば、CMでは、このオプションは「CyanogenMod設定」/「パフォーマンス」/「VMヒープサイズ」の下に表示されます。
注:この値を手動で設定すると、システムが正常に機能しなくなる可能性があることに注意してください。特に、デバイスで通常よりも小さい値を選択した場合に注意してください。
これは、CyanogenModを実行している4つの異なるデバイスmaxMemory()
から返された値とgetMemoryClass()
、それぞれに2つの異なる(手動で設定された)ヒープ値を使用したテスト結果です。
上記に加えて、Ice Cream Sandwichを実行するNovo7 Paladinタブレットでテストしました。これは基本的にICSのストックバージョンでしたが、OS全体を置き換えない単純なプロセスでタブレットをルート化し、特にヒープサイズを手動で調整できるインターフェイスを提供していませんでした。
そのデバイスの場合、結果は次のとおりです。
また、(以下のコメントのキショアによる):
そして(akauppiのコメントによる):
cmcromanceからのコメントによると:
そして(テンセントのコメントあたり):
他のデバイス
Honeycomb以降に利用できる特別なandroid:largeHeap = "true"マニフェストオプションを使用してこれら2つのメソッドをテストしていませんが、cmcromanceとtencentのおかげで、上記のようにサンプルのlargeHeap値がいくつかあります。
私の期待(上記largeHeap番号によってサポートされているように見える)このオプションはルート権限を取得OSを経由して、手動でヒープの設定と同様の効果を持っているということだろう-すなわち、それはの価値引き上げるmaxMemory()
残したままgetMemoryClass()
単独で。largeHeap設定を使用するアプリで許容されるメモリ量を示す別のメソッドgetLargeMemoryClass()があります。getLargeMemoryClass()のドキュメントには、「ほとんどのアプリケーションはこの量のメモリを必要とせず、代わりにgetMemoryClass()の制限を維持する必要がある」と記載されています。
私が正しく推測した場合、そのオプションを使用すると、ルート化されたOSを介してヒープをアップしたユーザーが使用可能にしたスペースを使用する場合と同じ利点(および危険)があります(つまり、アプリが追加のメモリを使用する場合、おそらく、ユーザーが同時に実行している他のアプリと同じようにうまく機能しません)。
メモリクラスは明らかに8MBの倍数である必要はないことに注意してください。
上記から、getMemoryClass()
特定のデバイス/ OS構成では結果が変わらないことがわかりますが、ユーザーがヒープを異なる方法で設定すると、maxMemory()の値が変化します。
私自身の実際の経験では、G1(メモリクラスは16)で、ヒープサイズとして24MBを手動で選択した場合、メモリ使用量が20MBにドリフトすることを許可されている場合でも、エラーなしで実行できます(おそらくそれは可能性があります)私はこれを試したことはありませんが、24MBにもなるでしょう。しかし、他の同様に大規模なアプリは、自分のアプリの便乗の結果としてメモリからフラッシュされる可能性があります。そして逆に、これらの他の高メンテナンスのアプリがユーザーによってフォアグラウンドに移動された場合、私のアプリはメモリからフラッシュされる可能性があります。
したがって、で指定されmaxMemory()
たメモリ量を超えることはできません。そして、あなたがすべきである試みることにより、指定された制限内に滞在しますgetMemoryClass()
。他の方法がすべて失敗した場合の1つの方法は、メモリを節約する方法でそのようなデバイスの機能を制限することです。
最後に、で指定されたメガバイト数を超えることを計画している場合getMemoryClass()
、私のアドバイスは、onStop()
/ onResume()
サイクルが発生してもユーザーのエクスペリエンスが実質的に中断されないように、アプリの状態の保存と復元に長く懸命に取り組むことです。
私の場合、パフォーマンス上の理由から、アプリを2.2以上を実行しているデバイスに制限しています。つまり、アプリを実行しているほとんどすべてのデバイスのmemoryClassは24以上になります。そのため、最大20MBのヒープを占有するように設計でき、ユーザーが同時に実行している可能性がある他のアプリと私のアプリがうまく機能することを確信できます。
ただし、2.2以上のバージョンのAndroidを古いデバイス(G1など)にロードしたrootユーザーは常に存在します。このような構成に遭遇した場合、理想的には、ターゲットにする必要があることを示しmaxMemory()
ている16MBよりもはるかに高い値を示すことができる場合でも、メモリ使用量を削減getMemoryClass()
する必要があります。アプリがその予算内で確実に機能することを保証できない場合は、少なくともonStop()
/ onResume()
がシームレスに機能することを確認してください。
getMemoryClass()
は、上記のダイアンハックボーン(hackbod)で示されているように、APIレベル5(Android 2.0)までしか使用できないため、以前のバージョンのOSを実行しているデバイスの物理ハードウェアが設計されていると想定できます。 16MB以下のヒープ領域を占有するアプリを最適にサポートするため。
これとは対照的に、maxMemory()
、マニュアルに従って、APIレベル1に戻ってすべての道利用可能である maxMemory()
、前のバージョン2.0で、おそらく16メガバイトの値を返しますが、私はない私(かなり後に)CyanogenModのバージョンのユーザーにそれを見ますは12MBまでのヒープ値を選択できます。これにより、ヒープ制限が低くなると考えmaxMemory()
られるため、2.0より前のバージョンのOSでも、値をテストし続けることをお勧めします。maxMemory()
許可されているよりも多くの値が必要な場合は、この値が16MBよりも低く設定されているという万が一の場合に、実行を拒否する必要があるかもしれません。
Debug.getNativeHeapSize()
トリックを行うと思います。しかし、それは1.0から存在しています。
このDebug
クラスには、割り当てやその他のパフォーマンスの問題を追跡するための優れたメソッドがたくさんあります。また、メモリ不足の状況を検出する必要がある場合は、をチェックしてくださいActivity.onLowMemory()
。
方法は次のとおりです。
アプリが使用できる最大ヒープサイズの取得:
Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();
アプリが現在使用しているヒープの量を取得します。
long usedMemory=runtime.totalMemory() - runtime.freeMemory();
アプリが現在使用できるヒープの量を取得する(使用可能なメモリ):
long availableMemory=maxMemory-usedMemory;
そして、それぞれをうまくフォーマットするために、あなたは使うことができます:
String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize);
これは最大ヒープサイズをバイト単位で返します。
Runtime.getRuntime().maxMemory()
私はActivityManager.getMemoryClass()を使用していましたが、CyanogenMod 7(他の場所ではテストしていません)では、ユーザーがヒープサイズを手動で設定すると、誤った値が返されます。
getMemoryClass
、数値がVMの利用可能なヒープサイズと同じでない可能性があることを示唆しているようであり、ドキュメントのgetNativeHeapSize
…は無口であるため、私は本当にRuntime.getRuntime().maxMemory()
最良の答えだと思います。
一部の操作は、Javaヒープスペースマネージャよりも高速です。しばらく操作を遅らせると、メモリ領域を解放できます。このメソッドを使用して、ヒープサイズエラーを回避できます。
waitForGarbageCollector(new Runnable() {
@Override
public void run() {
// Your operations.
}
});
/**
* Measure used memory and give garbage collector time to free up some
* space.
*
* @param callback Callback operations to be done when memory is free.
*/
public static void waitForGarbageCollector(final Runnable callback) {
Runtime runtime;
long maxMemory;
long usedMemory;
double availableMemoryPercentage = 1.0;
final double MIN_AVAILABLE_MEMORY_PERCENTAGE = 0.1;
final int DELAY_TIME = 5 * 1000;
runtime =
Runtime.getRuntime();
maxMemory =
runtime.maxMemory();
usedMemory =
runtime.totalMemory() -
runtime.freeMemory();
availableMemoryPercentage =
1 -
(double) usedMemory /
maxMemory;
if (availableMemoryPercentage < MIN_AVAILABLE_MEMORY_PERCENTAGE) {
try {
Thread.sleep(DELAY_TIME);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitForGarbageCollector(
callback);
} else {
// Memory resources are availavle, go to next operation:
callback.run();
}
}
AvailableMemoryPercentage
デバイスのメモリの現在の空き容量の計算式による。MIN_AVAILABLE_MEMORY_PERCENTAGE
カスタムパラメータであり、ガベージコレクタがジョブを実行するのを待つしきい値です。
Asus Nexus 7(2013)32Gig:getMemoryClass()= 192 maxMemory()= 201326592
Nexus 7でゲームのプロトタイプを作成しましたが、妻のジェネリック4.04タブレット(memoryclass 48、maxmemory 50331648)でほぼ即座にメモリ不足になることに気付きました。
メモリクラスが低いと判断した場合は、プロジェクトを再構築して、読み込むリソースを少なくする必要があります。
Javaで現在のヒープサイズを確認する方法はありますか?(デバッグ時にlogCatでそれをはっきりと見ることができますが、たとえばcurrentheap>(maxmemory / 2)が高品質のビットマップをアンロードして低品質をロードする場合など、コードでそれを適応させる方法を知りたいです
プログラム的にですか、それとも開発中やデバッグ中ですか?後者の場合、EclipseのDDMSパースペクティブからその情報を見ることができます。エミュレーター(接続されている物理的な電話など)が実行中の場合、アクティブなプロセスが左側のウィンドウにリストされます。それを選択することができ、ヒープ割り当てを追跡するオプションがあります。
Runtime rt = Runtime.getRuntime();
rt.maxMemory()
値はbです
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()
値はMBです
rt
?それはどこで宣言されていますか?