Androidでアプリケーションヒープサイズを検出する


145

Androidアプリで利用可能なアプリケーションヒープサイズをプログラムでどのように検出しますか?

SDKの今後のバージョンでこれを行う関数があると聞きました。いずれにせよ、1.5以上で機能するソリューションを探しています。


回答:


453

「使用可能なアプリケーションヒープサイズ」というフレーズについては、次の2つの方法で考えることができます。

  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));

このメソッドは、現在のデバイスの制限を適切に尊重したい場合や、他のアプリが/ サイクルに繰り返し強制されることなく実行する権利を失礼なものとして適切に尊重したい場合に、アプリ使用する必要があるヒープのおよそのメガバイト数を示しますelephantineアプリがAndroidジャグジーで入浴している間、メモリがフラッシュされます。onStop()onResume()

私が知る限り、この区別は明確に文書化されていませんが、この仮説を5つの異なるAndroidデバイスでテストし(下記を参照)、これが正しい解釈であることを自分の満足度で確認しました。

Androidのストックバージョンの場合、maxMemory()通常はに示されているのとほぼ同じメガバイト数getMemoryClass()(つまり、後者の値の約100万倍)を返します。

2つの方法が分岐する可能性がある唯一の状況(私が知っている)は、CyanogenModなどのAndroidバージョンを実行しているルート化されたデバイス上にあります。これにより、ユーザーは各アプリに許可するヒープサイズの大きさを手動で選択できます。たとえば、CMでは、このオプションは「CyanogenMod設定」/「パフォーマンス」/「VMヒープサイズ」の下に表示されます。

注:この値を手動で設定すると、システムが正常に機能しなくなる可能性があることに注意してください。特に、デバイスで通常よりも小さい値を選択した場合に注意してください。

これは、CyanogenModを実行している4つの異なるデバイスmaxMemory()から返された値とgetMemoryClass()、それぞれに2つの異なる(手動で設定された)ヒープ値を使用したテスト結果です。

  • G1:
    • VMヒープサイズが16MBに設定されている場合:
      • maxMemory:16777216
      • getMemoryClass:16
    • VMヒープサイズが24MBに設定されている場合:
      • maxMemory:25165824
      • getMemoryClass:16
  • Moto Droid:
    • VMヒープサイズが24MBに設定されている場合:
      • maxMemory:25165824
      • getMemoryClass:24
    • VMヒープサイズが16MBに設定されている場合:
      • maxMemory:16777216
      • getMemoryClass:24
  • Nexus One:
    • VMヒープサイズが32MBに設定されている場合:
      • maxMemory:33554432
      • getMemoryClass:32
    • VMヒープサイズを24MBに設定した場合:
      • maxMemory:25165824
      • getMemoryClass:32
  • Viewsonic GTab:
    • VMヒープサイズを32に設定した場合:
      • maxMemory:33554432
      • getMemoryClass:32
    • VMヒープサイズを64に設定した場合:
      • maxMemory:67108864
      • getMemoryClass:32

上記に加えて、Ice Cream Sandwichを実行するNovo7 Paladinタブレットでテストしました。これは基本的にICSのストックバージョンでしたが、OS全体を置き換えない単純なプロセスでタブレットをルート化し、特にヒープサイズを手動で調整できるインターフェイスを提供していませんでした。

そのデバイスの場合、結果は次のとおりです。

  • Novo7
    • maxMemory:62914560
    • getMemoryClass:60

また、(以下のコメントのキショアによる):

  • HTC One X
    • maxMemory:67108864
    • getMemoryClass:64

そして(akauppiのコメントによる):

  • Samsung Galaxy Core Plus
    • maxMemory:(コメントでは指定されていません)
    • getMemoryClass:48
    • largeMemoryClass:128

cmcromanceからのコメントによると:

  • Galaxy S3(Jelly Bean)大ヒープ
    • maxMemory:268435456
    • getMemoryClass:64

そして(テンセントのコメントあたり):

  • LG Nexus 5(4.4.3)通常
    • maxMemory:201326592
    • getMemoryClass:192
  • LG Nexus 5(4.4.3)の大きなヒープ
    • maxMemory:536870912
    • getMemoryClass:192
  • Galaxy Nexus(4.3)通常
    • maxMemory:100663296
    • getMemoryClass:96
  • Galaxy Nexus(4.3)大きなヒープ
    • maxMemory:268435456
    • getMemoryClass:96
  • Galaxy S4 Play Store Edition(4.4.2)通常
    • maxMemory:201326592
    • getMemoryClass:192
  • Galaxy S4 Play Store Edition(4.4.2)ラージヒープ
    • maxMemory:536870912
    • getMemoryClass:192

他のデバイス

  • Huawei Nexus 6P(6.0.1)通常
    • maxMemory:201326592
    • getMemoryClass:192

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よりも低く設定されているという万が一の場合に、実行を拒否する必要があるかもしれません。


2
@Carlハローカール、素晴らしい投稿ありがとうございます。そして、JellyBeanを使用してGalaxy S3でandroid:largeHeap = "true"オプションをテストしました。これが結果です。[maxMemory:256.0MB、memoryClass:64MB](maxMemoryはlargeheapオプションなしで64MBでした)
cmcromance

1
@Carl Haha大変光栄です!:)
cmcromance 2013

1
HTC One Xの場合:maxMemory:67108864 memoryClass:64
Kishore

1
LG Nexus 5(4.4.3)(通常):maxMemory:201326592、memoryClass:192 | LG Nexus 5(4.4.3)(大きなヒープ):maxMemory:536870912、memoryClass:192
ian.shaun.thomas

1
非常に美しく文書化されています。これをアンドロイドに提供してください。私はそのような適切なAndroidドキュメントを見つけることができません
Jimit Patel 2015

20

公式APIは次のとおりです。

これは2.0で導入され、より大きなメモリデバイスが登場しました。以前のバージョンのOSを実行しているデバイスが元のメモリクラス(16)を使用していると想定できます。


13

Debug.getNativeHeapSize()トリックを行うと思います。しかし、それは1.0から存在しています。

このDebugクラスには、割り当てやその他のパフォーマンスの問題を追跡するための優れたメソッドがたくさんあります。また、メモリ不足の状況を検出する必要がある場合は、をチェックしてくださいActivity.onLowMemory()


ニール、ありがとう。これは、デバッグをオフにしてアプリケーションを実行しているときに機能しますか?
hpique

2
私はこれにかなり慣れていませんが、ネイティブヒープは、質問が参照するアプリ(ダルビック)ヒープと同じだとは思いません。ネイティブヒープは、ネイティブコードによって割り当てられるビットマップデータのバッキングを提供し、アプリヒープはJavaアプリケーションデータを保持します。ネイティブヒープがアプリヒープの制限に対してカウントされ、3.0以降は実際に割り当てがアプリのヒープで発生することを知りました。ダイアンHackborn(hackbod)ここでは、このトピックに関する記事: stackoverflow.com/questions/1945142/bitmaps-in-android しかし、たとえ3.0のためには、また、アプリのヒープ上の非「ネイティブ」のデータがあります。
カール

1
最近のいくつかのAndroidアップデート(たぶんKitKat 4.4)以降、ビットマップはJVMヒープにあります。
akauppi 2014

13

方法は次のとおりです。

アプリが使用できる最大ヒープサイズの取得:

Runtime runtime = Runtime.getRuntime();
long maxMemory=runtime.maxMemory();

アプリが現在使用しているヒープの量を取得します。

long usedMemory=runtime.totalMemory() - runtime.freeMemory();

アプリが現在使用できるヒープの量を取得する(使用可能なメモリ):

long availableMemory=maxMemory-usedMemory;

そして、それぞれをうまくフォーマットするために、あなたは使うことができます:

String formattedMemorySize=Formatter.formatShortFileSize(context,memorySize); 

5

これは最大ヒープサイズをバイト単位で返します。

Runtime.getRuntime().maxMemory()

私はActivityManager.getMemoryClass()を使用していましたが、CyanogenMod 7(他の場所ではテストしていません)では、ユーザーがヒープサイズを手動で設定すると、誤った値が返されます。


のドキュメントはgetMemoryClass、数値がVMの利用可能なヒープサイズと同じでない可能性があることを示唆しているようであり、ドキュメントのgetNativeHeapSize…は無口であるため、私は本当にRuntime.getRuntime().maxMemory()最良の答えだと思います。
BoDは

3

一部の操作は、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();
  }
}

テスト済みグッド。これら2つのこと、availableMemoryPercentageとMIN_AVAILABLE_MEMORY_PERCENTAGEについて詳しく説明していただけますか?いくつかの説明?
Noor Hossain

1
AvailableMemoryPercentageデバイスのメモリの現在の空き容量の計算式による。MIN_AVAILABLE_MEMORY_PERCENTAGEカスタムパラメータであり、ガベージコレクタがジョブを実行するのを待つしきい値です。
Zon

1

Asus Nexus 7(2013)32Gig:getMemoryClass()= 192 maxMemory()= 201326592

Nexus 7でゲームのプロトタイプを作成しましたが、妻のジェネリック4.04タブレット(memoryclass 48、maxmemory 50331648)でほぼ即座にメモリ不足になることに気付きました。

メモリクラスが低いと判断した場合は、プロジェクトを再構築して、読み込むリソースを少なくする必要があります。
Javaで現在のヒープサイズを確認する方法はありますか?(デバッグ時にlogCatでそれをはっきりと見ることができますが、たとえばcurrentheap>(maxmemory / 2)が高品質のビットマップをアンロードして低品質をロードする場合など、コードでそれを適応させる方法を知りたいです


Nexus7-2013、getLargeMemoryClass()= 512前記
akauppi

0

プログラム的にですか、それとも開発中やデバッグ中ですか?後者の場合、EclipseのDDMSパースペクティブからその情報を見ることができます。エミュレーター(接続されている物理的な電話など)が実行中の場合、アクティブなプロセスが左側のウィンドウにリストされます。それを選択することができ、ヒープ割り当てを追跡するオプションがあります。


プログラム的にです。質問を明確にしました。ありがとう。
hpique

1
私はあなたがAndroidプラットフォームプログラマーの一つで、この記事を見てお勧め:stackoverflow.com/questions/2298208/...
スティーブ・ヘイリー

0
Runtime rt = Runtime.getRuntime();
rt.maxMemory()

値はbです

ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.getMemoryClass()

値はMBです


どんなタイプrt?それはどこで宣言されていますか?
FindOut_Quran 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.