Android アプリで使用可能なアプリケーション ヒープ サイズをプログラムで検出するにはどうすればよいですか?
SDK の以降のバージョンにはこれを実行する機能があると聞きました。いずれにせよ、1.5 以降で機能するソリューションを探しています。
ベストアンサー1
「使用可能なアプリケーション ヒープ サイズ」というフレーズについては、次の 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));
この方法では、およそメガバイトアプリのヒープすべき現在のデバイスの制限を適切に尊重し、巨大なアプリが Android のジャグジーで入浴している間に他のアプリがメモリから無礼にフラッシュアウトされ、 onStop()
/onResume()
サイクルに繰り返し強制されることなく他のアプリを実行する権利を尊重したい場合に使用します。
この区別は、私の知る限りでは明確に文書化されていませんが、私はこの仮説を 5 つの異なる Android デバイス (下記参照) でテストし、これが正しい解釈であることを自分自身で納得できるまで確認しました。
Android の標準バージョンの場合、maxMemory()
通常は に示されているのとほぼ同じメガバイト数getMemoryClass()
(つまり、後者の値の約 100 万倍) が返されます。
2つの方法が分岐する唯一の状況(私が知る限り)は、CyanogenModなどのAndroidバージョンを実行しているルート化されたデバイスの場合です。これにより、ユーザーは手動で選択する各アプリに許可するヒープ サイズの大きさ。たとえば、CM では、このオプションは「CyanogenMod 設定」/「パフォーマンス」/「VM ヒープ サイズ」の下に表示されます。
注意: この値を手動で設定すると、特にデバイスの通常の値よりも小さい値を選択した場合、システムに障害が発生する可能性があることに注意してください。
以下は、CyanogenMod を実行する 4 つの異なるデバイスによって返された値maxMemory()
とgetMemoryClass()
、それぞれに 2 つの異なる (手動で設定された) ヒープ値を使用したテスト結果です。
- G1:
- VM ヒープ サイズを 16 MB に設定した場合:
- 最大メモリ: 16777216
- 取得メモリクラス: 16
- VM ヒープ サイズを 24 MB に設定した場合:
- 最大メモリ: 25165824
- 取得メモリクラス: 16
- VM ヒープ サイズを 16 MB に設定した場合:
- モトドロイド:
- VM ヒープ サイズを 24 MB に設定した場合:
- 最大メモリ: 25165824
- 取得メモリクラス: 24
- VM ヒープ サイズを 16 MB に設定した場合:
- 最大メモリ: 16777216
- 取得メモリクラス: 24
- VM ヒープ サイズを 24 MB に設定した場合:
- ネクサスワン:
- VM ヒープ サイズを 32 MB に設定した場合:
- 最大メモリ: 33554432
- 取得メモリクラス: 32
- VM ヒープ サイズを 24 MB に設定した場合:
- 最大メモリ: 25165824
- 取得メモリクラス: 32
- VM ヒープ サイズを 32 MB に設定した場合:
- ビューソニックGTab:
- VM ヒープ サイズを 32 に設定した場合:
- 最大メモリ: 33554432
- 取得メモリクラス: 32
- VM ヒープ サイズを 64 に設定した場合:
- 最大メモリ: 67108864
- 取得メモリクラス: 32
- VM ヒープ サイズを 32 に設定した場合:
上記に加えて、Ice Cream Sandwich を実行している Novo7 Paladin タブレットでもテストしました。これは基本的に ICS の標準バージョンですが、OS 全体を置き換えない簡単なプロセスでタブレットをルート化しており、特にヒープ サイズを手動で調整できるインターフェイスは提供していません。
このデバイスの結果は次のとおりです。
- ノボ7
- 最大メモリ: 62914560
- 取得メモリクラス: 60
また(以下のコメントのKishore氏による):
- HTC ワンX
- 最大メモリ: 67108864
- 取得メモリクラス: 64
そして(akauppi のコメントによると):
- サムスンギャラクシーコアプラス
- maxMemory: (コメントでは指定されていません)
- 取得メモリクラス: 48
- ラージメモリクラス: 128
cmcromance からのコメント:
- Galaxy S3 (Jelly Bean) 大量
- 最大メモリ: 268435456
- 取得メモリクラス: 64
そして(テンセントのコメントによると):
- LG Nexus 5 (4.4.3) 通常
- 最大メモリ: 201326592
- 取得メモリクラス: 192
- LG Nexus 5 (4.4.3) 大きなヒープ
- 最大メモリ: 536870912
- 取得メモリクラス: 192
- ギャラクシーネクサス(4.3)通常
- 最大メモリ: 100663296
- 取得メモリクラス: 96
- Galaxy Nexus (4.3) 大きなヒープ
- 最大メモリ: 268435456
- 取得メモリクラス: 96
- Galaxy S4 Playストアエディション(4.4.2)通常
- 最大メモリ: 201326592
- 取得メモリクラス: 192
- Galaxy S4 Play Store Edition (4.4.2) 大容量
- 最大メモリ: 536870912
- 取得メモリクラス: 192
他のデバイス
- Huawei Nexus 6P (6.0.1) 通常
- 最大メモリ: 201326592
- 取得メモリクラス: 192
Honeycomb 以降で利用可能な特別な android:largeHeap="true" マニフェスト オプションを使用してこれら 2 つの方法をテストしたことはありません。ただし、cmcromance と tencent のおかげで、上で報告したように、いくつかのサンプルの largeHeap 値を入手できました。
私の期待(上記の largeHeap の数値によってサポートされているようです) このオプションは、ルート化された OS を介してヒープを手動で設定するのと同様の効果を持つということです。つまり、そのままにmaxMemory()
しておくとの値が増加しますgetMemoryClass()
。別のメソッド getLargeMemoryClass() は、largeHeap 設定を使用するアプリに許容されるメモリ量を示します。getLargeMemoryClass() のドキュメントには、「ほとんどのアプリケーションではこの量のメモリは必要なく、代わりに getMemoryClass() の制限内にとどまる必要があります」と記載されています。
私の推測が正しければ、そのオプションを使用すると、ルート化された OS を介してヒープを増やしたユーザーによって使用可能になったスペースを使用する場合と同じ利点 (および危険性) が得られます (つまり、アプリが追加のメモリを使用する場合、ユーザーが同時に実行している他のアプリとうまく連携しない可能性があります)。
メモリ クラスは 8MB の倍数である必要はないことに注意してください。
上記から、getMemoryClass()
特定のデバイス/OS 構成では結果は変わらないが、ユーザーがヒープを異なる方法で設定すると maxMemory() 値が変わることがわかります。
私の実際の経験では、G1(メモリクラスは16)では、ヒープサイズとして手動で24MBを選択すると、メモリ使用量が20MBにまで上昇してもエラーなしで実行できます(おそらく24MBまで上がる可能性がありますが、試していません)。しかし、私のアプリのメモリ使用量の多さのせいで、同様に大きなアプリがメモリからフラッシュされる可能性があります。そして、逆に、私のユーザーがこれらの他のメンテナンスに手間のかかるアプリをフォアグラウンドにすると、アプリがメモリからフラッシュされる可能性があります。
したがって、 で指定されたメモリ量を超えることはできませんmaxMemory()
。また、試すによって指定された制限内に収まるようにしますgetMemoryClass()
。他の方法がすべて失敗した場合、メモリを節約する方法でそのようなデバイスの機能を制限することが、これを実現する 1 つの方法となる可能性があります。
最後に、 で指定されたメガバイト数を超える予定の場合は、 /サイクルが発生しgetMemoryClass()
てもユーザー エクスペリエンスが実質的に中断されないように、アプリの状態の保存と復元に時間をかけて集中して取り組むことをお勧めします。onStop()
onResume()
私の場合、パフォーマンス上の理由から、アプリを 2.2 以降を実行しているデバイスに制限しています。つまり、アプリを実行しているほぼすべてのデバイスのメモリクラスは 24 以上になります。そのため、最大 20 MB のヒープを占有するように設計でき、ユーザーが同時に実行している可能性のある他のアプリとアプリがうまく連携することを確信できます。
しかし、古いデバイス(G1など)にAndroid 2.2以上のバージョンをロードしているルート化されたユーザーは常に存在します。そのような構成に遭遇した場合、16MBよりもずっと高いメモリ使用量が要求される場合でも、理想的にはメモリ使用量を削減する必要がありますmaxMemory()
。getMemoryClass()
すべきターゲットを絞ってください。そして、アプリがその予算内で確実に機能することを保証できない場合は、少なくともonStop()
/ がonResume()
シームレスに動作することを確認してください。
getMemoryClass()
は、上記の Diane Hackborn (hackbod) が指摘しているように、API レベル 5 (Android 2.0) までしか利用できないため、彼女のアドバイスどおり、以前のバージョンの OS を実行しているデバイスの物理ハードウェアは、16 MB 以下のヒープ領域を占有するアプリを最適にサポートするように設計されていると想定できます。
対照的にmaxMemory()
、ドキュメントによると、はAPIレベル1まで遡って利用可能です。2.0maxMemory()
より前のバージョンのは、おそらく16MBの値を返しますが、する私の (かなり後の) CyanogenMod バージョンでは、ユーザーは 12MB という低いヒープ値を選択できるようになっています。これにより、ヒープ制限が低くなると考えられます。そのため、maxMemory()
2.0 より前のバージョンの OS でも、引き続き値をテストすることをお勧めします。この値が 16MB よりも低く設定され、許可されている値よりも大きい値が必要な場合は、実行を拒否しなければならない場合もありますmaxMemory()
。