Androidのガベージコレクター


108

状況によってはガベージコレクターの呼び出しを示唆する多くのAndroidの回答を見てきました。

メモリを大量に消費する操作を行う前に、Androidでガベージコレクターを要求することは良い習慣ですか?そうでない場合は、OutOfMemoryエラーが発生したますか?

ガベージコレクターに頼る前に他に使用すべきものはありますか?

回答:


144

3.0ハニカムより前のバージョンの場合:はい、電話してください System.gc()

ビットマップを作成しようとしましたが、常に「メモリ不足エラー」が発生していました。しかし、私が電話したときSystem.gc()最初は大丈夫でした。

ビットマップを作成するとき、Androidはメモリ不足エラーで失敗することが多く、ガベージコレクションを最初に試みません。したがって、System.gc()、ビットマップを作成するのに十分なメモリがあります。

オブジェクトを作成するSystem.gc場合、必要に応じて自動的に呼び出されると思いますが、そうではありませんビットマップを作成する。失敗するだけです。

したがってSystem.gc()、ビットマップを作成する前に手動で呼び出すことをお勧めします。


39
これは、プレハニカムのビットマップデータがVMに格納されておらず、GCをトリガーしないためです。Honeycomb以降では問題になりません。
Timmmm

2
@Timmmmですが、実際には私の問題でした。largeheapをtrueに設定しただけです。
Lei Leyba 2015年

118

一般的に、ガベージコレクターが存在する場合、GCを手動で呼び出すことはお勧めできません。GCはヒューリスティックアルゴリズムを中心に構成されており、独自のデバイスに任せたときに最適に機能します。GCを手動で呼び出すと、パフォーマンスが低下することがよくあります。

ときどき、比較的まれな状況で、特定のGCが間違っていることに気づき、GCを手動で呼び出すと、パフォーマンスが向上することがあります。これは、すべてのケースでメモリを最適に管理する「完全な」GCを実装することは実際には不可能だからです。このような状況は予測が難しく、多くの微妙な実装の詳細に依存しています。「良い習慣」は、GCを単独で実行することです。GCへの手動呼び出しは例外です。これは、実際のパフォーマンスの問題が正式に確認された後にのみ想定する必要があります。


8
+1は、プラットフォームに依存しない適切な回答です。選択する前に、誰かがAndroid固有の答えを思いつくかどうかを確認するために待っています。
hpique

8
「パフォーマンス」がCPU効率よりも一般的なものを意味することを許可する場合、私はあなたが書いたものに同意します。Androidデバイスでは、パフォーマンスに対するユーザーの認識が最も重要です。たとえば、ユーザーがボタンを押している間にGCを実行することを開発者が好む場合があるため、ユーザーはGCに気づきません。
James K. Polk大統領、

5
多くの場合、ゲームの実行中はGCが実行されないことが重要です(これには、すべてのオブジェクトが事前に作成され、リサイクルされているか、または類似している必要があります)。ただし、ゲームが一時停止している場合は、GCに適したタイミングです。
パット

4
プレハニカム、ビットマップデータはVMメモリに保存されません。システムは、ビットマップが原因で非VMメモリが多すぎる場合は検出せず、GCを実行しBitmap.finalize()ます(非VMメモリを解放するメソッドが実行されます)。したがって、この場合には、あなたがすべき GCの頭やオーバーラン行くBitmap.recycle()か、System.gc()適切に。しかし、プレハニカムのみ。
Timmmm

1
@ThomasPornin-一方、アプリケーションプログラマーとして、OSが知らないことを知っています。これは、アプリがメモリの使用方法に大きな変更を加えようとする時期であり、混乱が少ないことです。ユーザーエクスペリエンスは、将来の任意の時点よりも、すぐに一時停止します。これは、アプリの使用方法が大きく変化するときに、頻繁に電話をかけない方が賢明な場合があることを意味します。これらは頻繁にGCを呼び出すべきではないという意味ではまれですが、ほとんどすべての重要なアプリにそのような既知の設計の瞬間があるという一般的です。
ToolmakerSteve 2017

26

ビットマップを適切に処理しない場合、Androidアプリケーションのメモリ不足は非常に一般的です。問題の解決策は

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

上記のコードでは、ビットマップをリサイクルしようとしたところ、使用済みのメモリ領域を解放できるため、メモリ不足は発生しない可能性があります。

それでも問題が解決しない場合は、これらの行も追加できます

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

詳細については、このリンクをご覧ください

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


注:GCの実行によって引き起こされるため、瞬間的に「一時停止」、されていない前にこれを実行することをお勧めし、各ビットマップの割り当て。

最適な設計は次のとおりです。

  1. 示されているコードによって、不要なったすべてのビットマップを解放しますif / recycle / null。(それを助ける方法を作ってください。)

  2. System.gc();

  3. 新しいビットマップを割り当てます。


19

OutOfMemoryErrorが発生した場合、通常はガベージコレクターを呼び出すには遅すぎます...

Android Developerからの引用は次のとおりです。

ほとんどの場合、ガベージコレクションは、大量の小さな短期間のオブジェクトが原因で発生します。世代別ガベージコレクターなどの一部のガベージコレクターは、アプリケーションが頻繁に中断されないように、これらのオブジェクトのコレクションを最適化できます。残念ながら、Androidガベージコレクターはこのような最適化を実行できません。したがって、パフォーマンスが重要なコードパスで短期間のオブジェクトを作成すると、アプリケーションのコストが非常に高くなります。

したがって、私の理解では、gcを呼び出す必要はありません。不要なオブジェクトの作成(ループ内のオブジェクトの作成など)を回避するために、より多くの労力を費やすことをお勧めします。


6
見積もりを逆に解釈できないのですか?多分メモリを消費する前にそれらのオブジェクトを収集するために、GCを手動で呼び出す必要があるかもしれません。
hpique

@hgpc:あなたが提案した方法で引用がどのように解釈されるのかわかりません。ドキュメンテーションは告白であり、彼らのGCが単純であることを認めていると思います。メモリが不足すると、フルGCが実行されます。
James K. Polk大統領、

複雑なオブジェクト、および複雑なオブジェクトを使用するフレームワークを最大限に活用することは、時期尚早の最適化よりも開発時間をより有効に使用する傾向があります。モバイルアプリのコーディング中に無意識のうちにパフォーマンスについて考え続けるため、最適化について心配することは、エンタープライズJavaよりもAndroidの方が簡単に陥ります。特に、パフォーマンスについて考えなければならないフレームワーク開発者は、注意を怠ると、その視点を公式ドキュメントに漏らしてしまいます。
LateralFractal 2014年

9

System.gc()Art Android 6.0.1 Nexus 5xでは動作しないようなので、Runtime.getRuntime().gc();代わりに使用します。


1
System.gc()のラッパー関数ですRuntime.getRuntime().gc()android.googlesource.com/platform/libcore/+/…を
Nathan F.

はい、ソースとドキュメントからは同じように見えますが、実際にSystem.gc()は機能しませんがRuntime.getRuntime().gc()機能します!
Ivan

7

私のアプリは多くの画像を管理していますが、OutOfMemoryErrorで終了しました。これは私を助けました。Manifest.xmlに追加

<application
....
   android:largeHeap="true"> 

9
グーグルはこれが好きではありません
ペドロパウロアモリム2014

1
@PedroPauloAmorimは理由を説明しますか?
マチャド

2
何をしているのかわからない場合は、largeHeapを使用しないでください。大きなヒープを使用すると、ガベージコレクターがメモリをクリアする前に大量のジャンクデータをループする必要があるため、ガベージコレクターの動作が非常に困難になります。
Prakash

7

一般的に言えば、System.gc()で明示的にGCを呼び出すべきではありません。IO講義(http://www.youtube.com/watch?v=_CruQY55HOk)もあり、GCの一時停止ログの意味と、Dalvikの方が知っているのでSystem.gc()を呼び出さないように説明しています。あなたよりそうするとき。

一方、上記で述べたように、AndroidのGCプロセス(他のすべてと同様)にはバグがある場合があります。つまり、Dalvik GCアルゴリズムはHotspotまたはJRockit JVMと同等ではなく、場合によっては問題が発生する可能性があります。それらの状況の1つは、ビットマップオブジェクトを割り当てるときです。これは、ヒープメモリと非ヒープメモリを使用し、メモリに制約のあるデバイス上のビットマップオブジェクトの1つの緩やかなインスタンスでOutOfMemory例外を発生させるのに十分なため、トリッキーです。そのため、このビットマップが不要になった後に呼び出すことは、一般に多くの開発者によって提案されており、一部の人々によっては良い習慣と見なされています。

ビットマップのネイティブメモリを安全に削除できるとマークされているため、ビットマップで.recycle()を使用することをお勧めします。これは非常にバージョンに依存していることを覚えておいてください。つまり、通常は古いバージョンのAndroid(3.0以前と思う)では必要ですが、それ以降のバージョンでは必要ありません。また、新しいバージョンのetherでそれを使用してもそれほど害はありません(これをループなどで実行しないでください)。新しいARTランタイムは、大きなオブジェクト用に特別なヒープ「パーティション」を導入したため、ここで大きく変化しましたが、ARTエーテルでこれを行うことはそれほど害にはならないと思います。

また、System.gc()に関する非常に重要な注意事項の1つです。このメソッドは、Dalvik(またはJVM)が応答する義務があるコマンドではありません。それは、仮想マシンに「面倒ではない場合はガベージコレクションを実行していただけませんか」と言うようなものだと考えてください。



3

RAMの使用状況に関する開発者ドキュメントは次のとおりなので、私はノーと言います

...
GC_EXPLICIT

そのようなあなたが呼び出すときのように、明示的なGC、GC() あなたがすべき避ける呼び出す代わりに、必要なときに実行するGCを信頼します)。

...

関連する部分を太字で強調しています。

YouTubeシリーズのAndroid Performance Patternsをご覧ください。アプリのメモリ使用量を管理するためのヒントが表示されます(sではなくAndroidのArrayMapsとSparseArrays を使用するなどHashMap)。


3

Xamarin開発者向けのクイックノート

あなたが呼び出すしたい場合System.gc()Xamarin.Androidアプリの中であなたが呼び出す必要がありますJava.Lang.JavaSystem.Gc()


2

の後にガベージコレクタを呼び出す必要はありませんOutOfMemoryError

それはJavadocが明確に述べています:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

そのため、ガベージコレクターはエラーを生成する前にメモリを解放しようとしましたが、失敗しました。


8
Android Javadocはそのことを述べておらず、おそらくその実装は異なります。d.android.com/reference/java/lang/OutOfMemoryError.html
hpique

これはAndroidには当てはまりません。ただし、繰り返しますが、ランタイムエーテルでOOEを処理することはできないため、これが当てはまるかどうかにかかわらず、それについて多くのことを行うことはできません。
IgorČordaš14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.