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


146

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


151
わかりました... 1つまっすぐにしましょう。何かが悪い習慣であり、奨励するものではないと思うからといって、投票に値するものにはなりません。これは明確で有効な質問であり、ガベージコレクションに依存せずにJavaでメモリを解放する方法があるかどうかを尋ねます。推奨されないこともありますが、一般的には役に立たないか、良いアイデアではありませんが、Felixが何を知っているかを知らずに必要になるシナリオがないことはわかりません。Felixはそれを使用することさえ計画していないかもしれません。彼はそれが可能かどうか知りたいだけかもしれません。それは決して投票に値しない。
ダニエルビンガム、

7
明確にするために、これはこれに反対票を投じた人を対象としたものであり、必ずしも以前のコメントではない。
ダニエルビンガム、

回答:


96

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

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

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

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

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


5
ガベージコレクターを強制的に実行します。ただし、メモリを強制的に解放するわけではありません...
Pablo Santa Cruz

13
パブロなし、GCを強制的に実行しません。
Jesper、

1
HotSpotVMのすべてのガベージコレクターがSystem.gc()完全に無視していると非常に信頼できる人から言われました。
Esko

1
winXpでは、Java SE GCはすべてのSystem.gc()またはほとんどすべてを実行しますが、APIドキュメントはそれを保証しません。
teodozjan 2012年

2
@パブロサンタクルスそれはメモリを解放しないとはどういう意味ですか?リークがあり、RAMの使用が安定しているように見えるプログラムでテストしたところです。そして、ダニエルはちょうどそれがそれを示唆しているだけだと言った、それで私がメソッドを呼び出すたびに使用されたラムのパーセンテージが常に安定しているのはなぜですか?あなたの人々は私を混乱させています。

65

オブジェクト参照をに明示的に設定することについて言及した人はいないようnullです。

たとえばList<String>、メソッドの最初にを宣言し、サイズが非常に大きくなったが、メソッドの途中までしか必要でなかったとします。この時点で、List参照をnullに設定して、メソッドが完了する前にガベージコレクターがこのオブジェクトを再利用できるようにすることができます(いずれにしても、参照はスコープ外になります)。

このテクニックを実際に使用することはめったにありませんが、非常に大きなデータ構造を扱う場合は検討する価値があります。


8
メソッドの一部にのみ使用されるオブジェクトに対して実際に多くの作業を行っている場合は、どちらかをお勧めします。メソッドが複雑すぎる、メソッドを前と後の部分に分割する、またはコードの前半にブロックを使用する(テストスクリプトには後半がより有用)
Peter Lawrey 2010

5
オブジェクト参照をnullに設定することが重要な場所は、オブジェクトが別の長期間有効なオブジェクト(または静的変数から)から参照される場合です。たとえば、ラージオブジェクトの長期間有効な配列があり、それらのオブジェクトのいずれかを使用しなくなった場合は、配列参照をnullに設定して、オブジェクトをGCで使用できるようにする必要があります。
Hot Licks 2014年

22
System.gc(); 

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

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

推奨されません。

編集:私は2009年に元の応答を書きました。それは現在2015年です。

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

  • 限られた数のマシンでGCを強制する場合は、ロードバランサーを現在のマシンから離れた場所に置き、接続されたクライアントへのサービスの提供が完了するのを待って、一定の時間が経過すると接続がハングするまでタイムアウトしてから、ただハードにするだけの価値があります。-JVMを再起動します。これはひどい解決策ですが、System.gc()を参照している場合、強制再起動は一時停止の可能性があります。
  • 別のガベージコレクタの使用を検討してください。たとえば、(過去6年間の新機能)G1コレクターは低休止モデルです。全体としてより多くのCPUを使用しますが、実行を強制停止しないでください。現在、サーバーCPUはほとんどすべてに複数のコアを備えているので、これは利用可能なA Really Good Tradeoffです。
  • メモリ使用量を調整するフラグを確認してください。特に新しいバージョンのJavaでは、長期間実行されるオブジェクトがそれほど多くない場合は、ヒープ内のnewgenのサイズを増やすことを検討してください。newgen(young)は、新しいオブジェクトが割り当てられる場所です。ウェブサーバーの場合、リクエスト用に作成されたすべてがここに配置されます。このスペースが小さすぎると、Javaはオブジェクトをより寿命の長いメモリにアップグレードするのに余分な時間を費やします。(newgenが少し小さすぎる場合は、その代金を支払うことになります。)たとえば、G1の場合:
    • XX:G1NewSizePercent(デフォルトは5です。おそらく問題ではありません。)
    • XX:G1MaxNewSizePercent(デフォルトは60です。おそらくこれを大きくします。)
  • ガベージコレクタに一時停止を長くしても問題ないことを伝えることを検討してください。これにより、GCがより頻繁に実行され、システムが残りの制約を維持できるようになります。G1の場合:
    • XX:MaxGCPauseMillis(デフォルトは200)

1
私自身の投稿にコメントすると、これはしばしば何もせず、繰り返し呼び出すと、JVMが不安定になるなどの原因になる可能性があります。それはあなたの犬をまたぐかもしれません。注意してアプローチしてください。
Dean J、

1
「gcメソッドの呼び出しがJVMの拡張作業を示唆している」の「推奨」の部分に重点を置きます
matt b

2
@ジェスパー、ディーンの答えは「提案」を述べています。実際、彼はメソッドのjavadocsからの正確なドキュメントを投稿しました...
matt b

2
@Software Monkey:はい、編集しただけかもしれません。しかし、ディーンJは明らかにアクティブだったので(ほんの数分前に投稿した)、彼にそうするように頼むのは礼儀だと思った。彼がいなかった場合、私はここに戻って編集を行い、コメントを削除しました。
ダニエルプライデン

1
また、推奨されない理由についても説明しておきます。JVMがGCを実行するための「提案」に注意を払うと、ほぼ確実にアプリの実行が遅くなります。
スティーブンC

11

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

これは不要です。Java GCが機能する方法は、それらへの参照がないオブジェクトを見つけることです。そのため、参照(=変数)aを持つオブジェクト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を検出し、それらも削除します。配列内の各参照をnullにしても、何も改善されることはありません。コード内のCPU時間と領域を使い果たすだけです(それは、それ以上害はありません。GCは、必要な方法を実行できます。 )。


5

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


Javaプログラムで249MBのチャンクを明示的に解放する必要がある場合、メモリ管理は私が最初に取り組みたいことではありません。
Marc DiMillo 2013

3
ただし、Javaヒープ内のストレージを解放しても、(一般的な場合)他のアプリがそのストレージを利用できるようにはなりません。
Hot Licks 2014年

5

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%が未使用の場合にのみそれを行うように見えますが、OSの物理メモリが不足している場合に、より積極的な解放になるかどうかはわかりません。


4

私はこれについて実験をしました。

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

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


"System.gc();を呼び出すと、すべての参照をnullに設定すると、パフォーマンスとメモリの占有率が向上する"とは確かに言えません。System.gc()の計算は非常に複雑だからです。また、System.gc()を呼び出して実際にガベージを収集した後でも、jvmはOSまたはシステムにメモリを返さない場合があります。JVMは将来の参照用にメモリを保持する場合があります。この回答を参照してください。
Md。Abu Nafee Ibna Zahid

3

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

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

free()の良いユースケースが本当にあると感じた場合は、それを質問に含めてください。そうすれば、あなたが何をしようとしているのかを確認できます。もっと良い方法がある可能性が高いです。


3

完全に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();

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


1

私の場合、私のJavaコードは近い将来他の言語に移植することを意図しているため(主にC ++)、少なくともリップサービスに料金を支払ってメモリを適切に解放し、後で移植プロセスを支援する必要があります。

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

しかし、私のケースは非常に特殊であり、これを実行するときにパフォーマンスの影響を受けていることを知っています。


1

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

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


1
これは実際には当てはまりません。Javaガベージコレクターは、それを正しく処理するのに十分スマートです。リストをnullにした場合(およびリスト内のオブジェクトに他の参照がない場合)、GCはリスト内のすべてのオブジェクトを再利用できます。それは現時点ではそれをしないことを選択するかもしれませんが、最終的にそれらを取り戻すでしょう。循環参照についても同様です。基本的に、GCが機能する方法は、orphranedオブジェクトを明示的に探し、それらを再利用することです。これがGCの全体の仕事です。あなたがそれを説明する方法はGCを全く役に立たなくするでしょう。
Dakkaron

1

Althrough Javaは、自動ガベージコレクションを提供します。オブジェクトのサイズと残りの量を知りたい場合があります。プログラム import java.lang;Runtime r=Runtime.getRuntime(); 使用mem1=r.freeMemory();してメモリを解放し、メモリの値を取得して、r.gc();メソッドの呼び出しと呼び出しを解放します。freeMemory()


1

JAVAからの推奨はnullに割り当てることです

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

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

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

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

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