アプリが使用できるRAMの最大量はいくつですか?


145

Androidオペレーティングシステムのメモリ管理に関するこの質問にかなり興味があるので、そのトピックについて非常に詳細な回答を期待しています。

私が知りたいこと:

  • Androidアプリ(システムアプリではない)が使用できるメモリ最大量メガバイト / RAM全体のパーセンテージ)はどれくらい ですか?
  • Androidのバージョンに違いはありますか?
  • デバイスのメーカーに関して何か違いはありますか?

最も重要な:

  • 実行時にアプリが使用できるRAMの量を決定するシステムに関しては、が考慮され、何に依存しますか(アプリごとの最大メモリが静的な数値ではないと想定)。

これまでに聞いたことがある(2013年まで):

  • 初期のAndroidデバイスのアプリごとの上限は16MBでした
  • その後、この上限は24MBまたは32MBに増加しました

何が私をとても興味深くしているのですか?

これらの制限はどちらも非常に低いです。

最近、デバイスのRAMを確認するためにAndroidタスクマネージャーをダウンロードしました。私が気づいたのは、約40〜50メガバイトのRAMを使用するアプリケーションがあることです。これは、前述の最大RAM使用量(たとえば、32 MB)を超えたものです。では、Androidはアプリが使用できるRAMの量をどのように決定するのでしょうか?アプリがその制限を超える可能性はありますか?

さらに、約30〜40メガバイトを使用すると、一部のアプリがOutOfMemoryExceptionでクラッシュします(システムによって強制終了されましたか?)。一方、私は自分の電話で100 MB以上を使用しているアプリを実行していますが、おそらくメモリリークが原因で、クラッシュしたり強制終了したりすることはありません。そのため、 RAMをどれだけ節約できるかを判断する際には、アプリ自体にも明らかに依存します。これはどのようにして可能ですか?(私は768 MB RAMのHTC One Sでテストを実施しました)

免責事項:私は、Android Task Managerアプリとは一切関係ありません。

回答:


119

Androidアプリ(システムアプリではない)が使用できるメモリの最大容量(メガバイト/ RAM全体のパーセンテージ)はどれくらいですか?

デバイスによって異なります。getMemoryClass()onActivityManagerは、コードが実行されているデバイスの値を示します。

Androidのバージョン間に違いはありますか?

はい、OS要件が年々増加し、デバイスがそれに合わせて調整する必要がある限り、

デバイスのメーカーに関して違いはありますか?

はい、製造元がデバイスを製造している限り、サイズはデバイスによって異なります。

アプリが使用できるRAMの量を決定する際に考慮に入れられる「副次的要素」はどれですか。

「サイドファクター」の意味がわかりません。

初期のデバイスのアプリごとの上限は16MBでした。以降のデバイスでは、24MBまたは32MBに増加しました

その通りです。解像度が高いほどビットマップも大きくなるため、画面解像度は重要な決定要因です。そのため、タブレットや高解像度の携帯電話では、まだ値が高くなる傾向があります。たとえば、48MBヒープのデバイスが表示されますが、それ以上の値があったとしても驚かないでしょう。

アプリがその制限を超える可能性はありますか?

あなたは、そのアプリの作者が彼が何をしているか知っていると仮定します。ことを考慮すると、アプリのメモリ使用量を決定するために、コアのAndroidエンジニアのために困難であり、私は、問題のアプリが必ずしも特に正確な結果を提供していることを前提としないでしょう。

そうは言っても、ネイティブコード(NDK)はヒープ制限の対象ではありません。また、Android 3.0以降、アプリは通常「数百MBの範囲の「大きなヒープ」をリクエストできますが、ほとんどのアプリではこれは不適切なフォームと見なされます。

さらに、約30〜40メガバイトを使用すると、一部のアプリがOutOfMemoryExceptionでクラッシュすることに気付きました。

Androidガベージコレクターは圧縮ガベージコレクターではないことに注意してください。例外は本当にあるべきですがCouldNotFindSufficientlyLargeBlockOfMemoryException、それはおそらく余りに冗長であると考えられました。要求されたブロックを割り当てるOutOfMemoryExceptionことができなかったことを意味します。ヒープを完全に使い果たしたわけではありません。


テーブルについて理解できません。大きな解像度である1080 x 1920の解像度を持つXperia Xモバイルと、800 x 1280の解像度である別のデバイスのSamsung Tab 4を持っているので、同じRAM占有率をとります。 3 GBのRAMとタブには1.5 GBのRAMが付属しているため、タブレットは大画面のため、大きなRAMを占有しますか?
Rahul Mandaliya 2017

@RahulMandaliya:すみませんが、あなたの懸念やこの質問との関係がわかりません。懸念事項を詳しく説明する別のスタックオーバーフローの質問を開いてください。
CommonsWare 2017

15

2018年末なので、状況は変わりました。

まず、アプリを実行し、Android StudioでAndroid Profilerタブを開きます。どれだけのメモリを消費するかがわかります。驚かれることでしょうが、大量のRAMを割り当てることができます。

また、メモリ管理の詳細を確認できるMemory Profilerの使用方法の詳細な手順が記載された公式ドキュメントのすばらしい記事ここにあります。

しかし、ほとんどの場合、通常のAndroidプロファイラーで十分です。

ここに画像の説明を入力してください

通常、アプリは50MbのRAM割り当てで開始しますが、メモリへの写真の読み込みを開始すると、すぐに最大90Mbにジャンプします。写真がプリロードされたViewPager(各3.5Mb)でアクティビティを開くと、数秒で190Mbを簡単に取得できます。

しかし、これはメモリ管理に問題があるという意味ではありません。

私ができる最善のアドバイスは、ガイドラインとベストプラクティスに従い、画像の読み込みにトップライブラリ(Glide、Picasso)を使用することです。


しかし、何かを調整する必要があり、手動で割り当てることができるメモリの量を本当に知る必要がある場合は、合計空きメモリを取得し、その中からあらかじめ決められた部分(%)を計算できます。私の場合、復号化した写真をメモリにキャッシュする必要があったので、ユーザーがリストをスライドするたびに復号化する必要はありません。

この目的のために、すぐに使えるLruCacheクラスを使用できます。これは、オブジェクトが割り当てるメモリ量(またはインスタンスの数)を自動的に追跡し、最も古いものを削除して、使用履歴によって最新のものを保持するキャッシュクラスです。 これは、使い方の素晴らしいチュートリアルです。

私の場合、サムとアタッチメントの2つのキャッシュインスタンスを作成しました。シングルトンアクセスで静的にして、アプリ全体でグローバルに使用できるようにしました。

キャッシュクラス:

public class BitmapLruCache extends LruCache<Uri, byte[]> {

    private static final float CACHE_PART_FOR_THUMBS_PRC = 0.01f; // 1% (Nexus 5X - 5Mb)
    private static final float CACHE_PART_FOR_ATTACHMENTS_PRC = 0.03f;// 3% (Nexus 5X - 16Mb)
    private static BitmapLruCache thumbCacheInstance;
    private static BitmapLruCache attachmentCacheInstance;

public static synchronized BitmapLruCache getDecryptedThumbCacheInstance() {
    if (thumbCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_THUMBS_PRC);
    //L.log("creating BitmapLruCache for Thumb with size: " + cacheSize + " bytes");
        thumbCacheInstance = new BitmapLruCache(cacheSize);
        return thumbCacheInstance;
    } else {
        return thumbCacheInstance;
    }
}

public static synchronized BitmapLruCache getDecryptedAttachmentCacheInstance() {
    if (attachmentCacheInstance == null) {

        int cacheSize = getCacheSize(CACHE_PART_FOR_ATTACHMENTS_PRC);
    //            L.log("creating BitmapLruCache for Attachment with size: " + cacheSize + " bytes");
        attachmentCacheInstance = new BitmapLruCache(cacheSize);
        return attachmentCacheInstance;
    } else {
        return attachmentCacheInstance;
    }
}

private BitmapLruCache(int maxSize) {
    super(maxSize);
}

public void addBitmap(Uri uri, byte[] bitmapBytes) {
    if (get(uri) == null && bitmapBytes != null)
        put(uri, bitmapBytes);
}

public byte[] getBitmap(Uri uri) {
    return get(uri);
}


@Override
protected int sizeOf(Uri uri, byte[] bitmapBytes) {
    // The cache size will be measured in bytes rather than number of items.
    return bitmapBytes.length;
}
}

これは私が利用可能な空きRAMを計算する方法であり、どれだけそれをかむことができます:

private static int getCacheSize(float partOfTotalFreeMemoryToUseAsCache){
    final long maxMemory = Runtime.getRuntime().maxMemory();
    //Use ... of available memory for List Notes thumb cache
    return (int) (maxMemory * partOfTotalFreeMemoryToUseAsCache);
}

そしてこれは私がアダプタでそれを使用してキャッシュされたイメージを取得する方法です:

byte[] decryptedThumbnail = BitmapLruCache.getDecryptedThumbCacheInstance().getBitmap(thumbUri);

バックグラウンドスレッドのキャッシュに設定する方法(通常のAsyncTask):

BitmapLruCache.getDecryptedThumbCacheInstance().addBitmap(thumbUri, thumbBytes); 

私のアプリはAPI 19以上を対象としているため、デバイスは古くなく、利用可能なRAMのこれらの部分は、私の場合(1%および3%)のキャッシュに十分です。

面白い事実: Androidには、アプリに割り当てられたメモリの量を取得するためのAPIやその他のハックはありません。さまざまな要因に基づいてオンザフライで計算されます。


PS私は静的クラスフィールドを使用してキャッシュを保持していますが、最新のAndroidガイドラインによると、その目的でViewModelアーキテクチャコンポーネントを使用することをお勧めします。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.