87

実行時に残りのメモリを JVM で使用できるようにする良い方法はありますか? この使用例は、OutOfMemory エラーで突然終了するのではなく、「too many people using this, try again later」という素敵なエラー メッセージで新しい接続を拒否することで、メモリの制限に近づいたときに適切に失敗する Web サービスを持つことです。 .

これは、事前に各オブジェクトのコストを計算/見積もりすることとは関係がないことに注意してください。原則として、オブジェクトが使用するメモリの量を推定し、その推定に基づいて新しい接続を拒否することはできますが、それはハック/壊れやすいようです。

4

9 に答える 9

107

William Brendel によるこのサンプルは、役に立つかもしれません。

編集:私はもともとこのサンプルを提供しました(別のトピックに関するウィリアムブレンデルの回答へのリンク)。そのトピックの作成者 (Steve M) は、マルチプラットフォーム Java アプリケーションを作成したいと考えていました。具体的には、ユーザーは、実行中のマシンのリソース (ディスク容量、CPU、およびメモリ使用量) を評価する手段を見つけようとしていました。

これは、そのトピックで与えられた回答のインライン トランスクリプトです。ただし、このトピックについては、私の回答が承認済みとしてマークされているにもかかわらず、理想的な解決策ではないことが指摘されています。

public class Main {
  public static void main(String[] args) {
  /* Total number of processors or cores available to the JVM */
  System.out.println("Available processors (cores): " + 
  Runtime.getRuntime().availableProcessors());

  /* Total amount of free memory available to the JVM */
  System.out.println("Free memory (bytes): " + 
  Runtime.getRuntime().freeMemory());

  /* This will return Long.MAX_VALUE if there is no preset limit */
  long maxMemory = Runtime.getRuntime().maxMemory();
  /* Maximum amount of memory the JVM will attempt to use */
  System.out.println("Maximum memory (bytes): " + 
  (maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory));

  /* Total memory currently in use by the JVM */
  System.out.println("Total memory (bytes): " + 
  Runtime.getRuntime().totalMemory());

  /* Get a list of all filesystem roots on this system */
  File[] roots = File.listRoots();

  /* For each filesystem root, print some info */
  for (File root : roots) {
    System.out.println("File system root: " + root.getAbsolutePath());
    System.out.println("Total space (bytes): " + root.getTotalSpace());
    System.out.println("Free space (bytes): " + root.getFreeSpace());
    System.out.println("Usable space (bytes): " + root.getUsableSpace());
  }
 }
}

Runtime.getRuntime().freeMemory()ユーザーの Christian Friesは、メモリ不足エラーが発生するまでに割り当てられる可能性のあるメモリ量を で求めるのは間違っていると指摘しています。

documentationから、署名の戻り値は次のRuntime.getRuntime().freeMemory()とおりです。

戻り値:将来割り当てられるオブジェクトに現在使用可能なメモリの総量の概算 (バイト単位)。

ただし、ユーザーの Christian Fries は、この関数は誤解されている可能性があると主張しています。彼は、メモリ不足エラーが発生するまでに割り当てられる可能性のあるメモリの概算量 (空きメモリ) は、次の式で与えられる可能性が高いと主張しています。

long presumableFreeMemory = Runtime.getRuntime().maxMemory() - allocatedMemory;

によってallocatedMemory与えられます:

long allocatedMemory = 
  (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());

ここで重要なのは、空きメモリの概念の不一致です。その 1 つは、オペレーティング システムが Java 仮想マシンに提供するメモリです。もう 1 つは、Java 仮想マシン自体によって実際に使用されているメモリ ブロックのチャンクを構成する合計バイト数です。

Java アプリケーションに割り当てられたメモリが Java 仮想マシンによってブロック単位で管理されることを考慮すると、Java 仮想マシンで使用できる空きメモリの量は、Java アプリケーションで使用できるメモリと正確に一致しない場合があります。

具体的には、Christian Fries は、-mxまたは-Xmxフラグを使用して、Java 仮想マシンで使用できるメモリの最大量を設定することを示しています。彼は、次の機能の違いに注目しています。

/* Returns the maximum amount of memory available to 
   the Java Virtual Machine set by the '-mx' or '-Xmx' flags. */
Runtime.getRuntime().maxMemory();

/* Returns the total memory allocated from the system 
   (which can at most reach the maximum memory value 
   returned by the previous function). */
Runtime.getRuntime().totalMemory();

/* Returns the free memory *within* the total memory 
   returned by the previous function. */
Runtime.getRuntime().freeMemory();

Runtime.getRuntime().freeMemory()クリスチャンは、実際には推定可能な空きメモリと呼ばれるものを返すと述べて、彼の答えを締めくくっています。将来のメモリ割り当てがその関数によって返される値を超えていなくても、Java 仮想マシンがホスト システムによって割り当てられた実際のメモリ チャンクをまだ受け取っていない場合は、java.lang.OutOfMemoryError依然として が生成される可能性があります。

最終的に、使用する適切な方法は、アプリケーションの詳細に依存する度合いが異なります。

役に立つかもしれない別のリンクを提供します。これは、使用されるデフォルトの Java ヒープ サイズの決定について、ユーザー Richard Dormand によって作成され、stone333 によって回答された質問です。

于 2012-10-09T20:22:45.263 に答える
8

ランタイム メソッドを使用することに加えて、次を使用して追加のメモリ情報を取得できます。

MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heap = memBean.getHeapMemoryUsage();
MemoryUsage nonheap = memBean.getNonHeapMemoryUsage();

MemoryUsageは、init、used、commited、および max の値を提供します。これは、メモリをポーリングしてログに記録するメモリ モニタ スレッドを作成し、時間の経過に伴うメモリ使用量の履歴を提供する場合に役立ちます。エラーが発生するまでのメモリ使用量を時系列で確認すると役立つ場合があります。

これを極端に行いたい場合は、ヒープ ダンプ スレッドを作成します。メモリ使用量を時間の経過とともに監視し、特定のしきい値を超えた場合は次の手順を実行します (これは JBoss 5.0 で機能します - 使用量は異なる場合があります)。

// init code
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean diagBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); 

// loop code
// add some code to figure if we have passed some threshold, then

File heapFile = new File(outputDir, "heap-" + curThreshold + ".hprof");
log.info("Dumping heap file " + heapFile.getAbsolutePath());
diagBean.dumpHeap(heapFile.getAbsolutePath(), true);

後で、これらのヒープ ダンプ ファイルを Eclipseメモリ アナライザーまたは同様のツールで確認して、メモリ リークなどをチェックできます。

于 2012-10-09T23:11:03.547 に答える
7

他の回答に加えて、 SoftReferencesを使用するアプリにキャッシュがある可能性があるため、これを行うことは必ずしも良い考えではないことに注意してください。

このようなキャッシュは、JVM がメモリ制限に達するとすぐにメモリを解放します。十分な空きメモリがない場合でも、メモリを割り当てると、最初にメモリがソフト参照によって解放され、割り当てに使用できるようになります。

于 2012-10-09T20:25:22.713 に答える
1

いつでも電話できますRuntime.getRuntime().freeMemory()

オブジェクトのコストを取得するという問題の残りの半分は、私にはもっと問題があるように思えます。

より良い解決策は、新しい接続を拒否することなく定格負荷の 150% を適切に受け入れることができるように、Web サービスをクラスター化およびスケーリングする方法を考え出すことだと思います。コード ハックよりもサイジング エクササイズの方が優れたソリューションが得られるように思えます。

于 2012-10-09T20:21:27.760 に答える
0

Runtime.getRuntime().freeMemory()実行時にその時点で JVM の空きメモリを取得する方法です。それは良い方法ですか(または)、アプリケーションに完全に依存します。

于 2012-10-09T20:21:47.047 に答える
0
long freeMemory = Runtime.getRuntime().freeMemory();
于 2012-10-09T20:22:38.163 に答える