web-dev-qa-db-ja.com

Javaでメモリを解放する方法は?

Cのfree()関数と同様に、Javaでメモリを解放する方法はありますか?または、オブジェクトをnullに設定し、GCのみに依存していますか?

133
Felix

Javaはマネージメモリを使用するため、メモリを割り当てることができる唯一の方法はnew演算子を使用することであり、メモリを解放することができる唯一の方法はガベージコレクタに依存することです。

この メモリ管理ホワイトペーパー (PDF)は、何が起こっているのかを説明するのに役立ちます。

System.gc()を呼び出して、ガベージコレクターをすぐに実行することを提案することもできます。ただし、Java Runtimeは、コードではなく最終決定を行います。

Javaドキュメント によると、

Gcメソッドを呼び出すと、Java仮想マシンは、現在使用しているメモリをすぐに再利用できるようにするために、未使用オブジェクトのリサイクルに努力することを示唆します。メソッド呼び出しから制御が戻ると、Java仮想マシンは、破棄されたすべてのオブジェクトからスペースを回収するために最大限の努力をしました。

91
Daniel Pryden

オブジェクト参照をnullに明示的に設定することについて誰も言及していないようです。これは、考慮したいメモリを「解放」するための正当な手法です。

たとえば、メソッドの先頭でList<String>を宣言すると、サイズが非常に大きくなりますが、メソッドの途中までしか必要ありませんでした。この時点で、List参照をnullに設定すると、メソッドが完了する前にガベージコレクターがこのオブジェクトを潜在的に回収できるようになります(とにかく参照はスコープ外になります)。

私は実際にこの手法を使用することはめったにありませんが、非常に大きなデータ構造を扱う場合は検討する価値があることに注意してください。

63
Adamski
System.gc(); 

ガベージコレクターを実行します。

gcメソッドの呼び出しsuggestsは、Java仮想マシンが現在使用しているメモリをすぐに再利用できるようにするために、未使用オブジェクトのリサイクルに努力することを示唆しています。メソッド呼び出しから制御が戻ると、Java仮想マシンは、破棄されたすべてのオブジェクトからスペースを回収するために最大限の努力をしました。

非推奨。

編集:2009年に元の回答を書きました。2015年です。

ガベージコレクターは、Javaが登場してから20年以内に着実に改善されました。この時点で、ガベージコレクタを手動で呼び出す場合は、他のアプローチを検討することをお勧めします。

  • 限られた数のマシンでGCを強制している場合、ロードバランサーポイントを現在のマシンから離して、それを待つ価値があるかもしれません接続されたクライアントへのサービスを終了し、接続がハングするための一定期間後にタイムアウトし、JVMをハード再起動します。これはひどい解決策ですが、System.gc()を見ていると、強制的な再起動が一時的なギャップになる可能性があります。
  • 別のガベージコレクタの使用を検討してください。たとえば、G1コレクター(過去6年で新規)は、一時停止の少ないモデルです。全体としてより多くのCPUを使用しますが、実行時にハードストップを強制しないことをお勧めします。サーバーCPUのほとんどすべてに複数のコアが搭載されているため、これは本当に有効なトレードオフです。
  • メモリ使用量を調整するフラグを見てください。特にJavaの新しいバージョンでは、長期実行オブジェクトがそれほど多くない場合は、ヒープ内のnewgenのサイズを増やすことを検討してください。 newgen(young)は、新しいオブジェクトが割り当てられる場所です。 Webサーバーの場合、リクエストに対して作成されたすべてがここに置かれます。このスペースが小さすぎる場合、Javaはオブジェクトをより長いメモリにアップグレードするのに余分な時間を費やします。 (newgenが少し小さすぎる場合は、支払います。)たとえば、G1:
    • XX:G1NewSizePercent(デフォルトは5。おそらく問題ではない。)
    • XX:G1MaxNewSizePercent(デフォルトは60。おそらくこれを上げる。)
  • ガベージコレクターに、一時停止時間が長くても大丈夫でないと伝えることを検討してください。これにより、GCが頻繁に実行され、システムが残りの制約を保持できるようになります。 G1:
    • XX:MaxGCPauseMillis(デフォルトは200)。
22
Dean J

*「将来的に適切に削除するために、プレースホルダーとしてnulling変数に個人的に依存しています。たとえば、配列自体を実際に削除する(nullにする)前に、配列のすべての要素を無効にします。」

これは不要です。 Java GCが機能する方法は、それらへの参照を持たないオブジェクトを見つけることです。したがって、オブジェクトを指す参照(=変数)aを持つObject xがある場合、GCはそれを削除しません。 、そのオブジェクトへの参照があるため:

a -> x

あなたがこれよりもnをnullする場合:

a -> null
     x

したがって、xにはそれを指す参照がなく、削除されます。 xとは異なるオブジェクトを参照するようにaを設定すると、同じことが起こります。

したがって、オブジェクトx、y、zを参照する配列arrと、配列を参照する変数aがある場合、次のようになります。

a -> arr -> x
         -> y
         -> z

あなたがこれよりもnをnullする場合:

a -> null
     arr -> x
         -> y
         -> z

したがって、GCはarrに参照が設定されていないことを検出して削除し、次の構造を提供します。

a -> null
     x
     y
     z

これでGCはx、y、zを見つけて、それらも削除します。配列内の各参照を無効にしても何も改善されず、コード内でCPU時間とスペースが消費されるだけです(つまり、それ以上の損害はありません。GCは、本来の方法で実行できます) )。

11
Dakkaron

プログラム(Javaであるかどうかに関係なく)からメモリを解放したい正当な理由は、オペレーティングシステムレベルで他のプログラムがより多くのメモリを利用できるようにするためです。 Javaアプリケーションが250MBを使用している場合、それを1MBに強制し、249MBを他のアプリで使用できるようにすることができます。

5
Yios

Yiannis XanthopoulosとHot Licksによる回答とコメントを拡張するには(申し訳ありませんが、まだコメントできません!)、次の例のようにVMオプションを設定できます。

-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30

私のjdk 7では、VMがアイドル状態のときにGC後に30%を超えるヒープが解放されると、未使用のVMメモリが解放されます。これらのパラメーターを調整する必要があるでしょう。

以下のリンクでは強調されていませんが、一部のガベージコレクターはこれらのパラメーターに従わない場合があり、デフォルトでJavaがこれらのいずれかを選択する場合があります。 (したがって、上記のUseG1GC引数)。

VM引数

更新:Java 1.8.0_73の場合、JVMがデフォルト設定で少量を時々リリースするのを見てきました。ただし、ヒープの〜70%が使用されていない場合にのみ実行されるように見えます。

5
nsandersen

私はこれを実験しました。

System.gc();がガベージコレクターの実行のみを提案しているのは事実です。

ただし、すべての参照をnullに設定した後にSystem.gc();を呼び出すと、パフォーマンスとメモリ占有率が向上します。

4
Hemant Yadav

本当にメモリブロックを割り当てて解放したい場合は、直接ByteBuffersでこれを行うことができます。メモリを解放する移植性のない方法もあります。

ただし、提案されているように、Cでメモリを解放する必要があるからといって、これを行う必要があるとは限りません。

Free()の優れたユースケースが本当にあると感じた場合は、質問にそれを含めてください。そうすれば、あなたがやろうとしていることを確認できます。

3
Peter Lawrey

完全に javacoffeebreak.com/faq/faq0012.html から

低優先度のスレッドは、ユーザーのガベージコレクションを自動的に処理します。アイドル時間中にスレッドが呼び出され、以前にJavaのオブジェクトに割り当てられていたメモリの解放を開始できます。しかし、心配しないでください-それはあなたのオブジェクトを削除しません!

オブジェクトへの参照がない場合、ガベージコレクターにとって公平なゲームになります。何らかのルーチン(C++のfreeなど)を呼び出すのではなく、オブジェクトへのすべての参照をnullに割り当てるか、新しいクラスを参照に割り当てます。

例:

public static void main(String args[])
{
  // Instantiate a large memory using class
  MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192);

  // Do some work
  for ( .............. )
  {
      // Do some processing on myClass
  }

  // Clear reference to myClass
  myClass = null;

  // Continue processing, safe in the knowledge
  // that the garbage collector will reclaim myClass
}

コードが大量のメモリを要求しようとしている場合、ガベージコレクターに低優先度のスレッドとして許可するのではなく、スペースの再利用を開始するように要求できます。これを行うには、次をコードに追加します

System.gc();

ガベージコレクターは空き領域の再生を試み、可能な限り多くのメモリを再生しながら、アプリケーションの実行を継続できます(特定のプラットフォームではメモリの断片化の問題が発生する場合があります)。

2
displayname

* "たとえば、サイズが非常に大きくなるメソッドの先頭でListを宣言したが、メソッドの途中までしか必要ではなかったとします。この時点で、 nullへの参照をリストし、メソッドが完了する前にガベージコレクターがこのオブジェクトを再利用できるようにします(そして、参照はとにかくスコープから外れます)。*

これは正しいですが、このソリューションは一般化できない場合があります。 Listオブジェクト参照をnullに設定すると、メモリがガベージコレクションに使用できるようになりますが、これはプリミティブ型のListオブジェクトにのみ当てはまります。 Listオブジェクトに代わりに参照タイプが含まれる場合、Listオブジェクト= nullを設定しても、リストに含まれる参照タイプのいずれも参照解除されません。この場合、List object = nullを設定すると、ガベージコレクションアルゴリズムがオブジェクトが孤立していると判断できるほどスマートでない限り、オブジェクトがガベージコレクションに利用できない参照型が孤立します。

1
Gothri

私の場合、Javaコードは近い将来に他の言語(主にC++)に移植される予定なので、少なくとも移植プロセスを支援するためにメモリを適切に解放するためにリップサービスを支払う必要がありますオン。

私は個人的に、将来適切に削除するためのプレースホルダーとしてnull変数を使用しています。たとえば、配列自体を実際に削除する(nullにする)前に、配列のすべての要素を無効にする時間をとります。

しかし、私の場合は非常に特殊であり、これを行うときにパフォーマンスが低下していることを知っています。

1
Oskuro

Javaからの推奨事項は、nullに割り当てることです

から https://docs.Oracle.com/cd/E19159-01/819-3681/abebi/index.html

不要になった変数に明示的にnull値を割り当てると、ガベージコレクターが安全に再生できるメモリの部分を識別するのに役立ちます。 Javaはメモリ管理を提供しますが、メモリリークや過剰なメモリ使用を防ぐことはできません。

アプリケーションは、オブジェクト参照を解放しないことにより、メモリリークを引き起こす可能性があります。そうすることで、Javaガベージコレクターがこれらのオブジェクトを再利用できなくなり、使用されるメモリ量が増加します。変数の使用後に変数への参照を明示的に無効化すると、ガベージコレクターがメモリを再利用できます。

メモリリークを検出する1つの方法は、プロファイリングツールを使用して、各トランザクションの後にメモリスナップショットを取得することです。定常状態のリークフリーアプリケーションは、ガベージコレクション後に安定したアクティブヒープメモリを表示します。

1
user3869837