1. ホーム
  2. java

[解決済み] Javaで使用可能なメモリを取得する

2023-04-22 19:10:13

質問

実行時にJVMに利用可能な残りのメモリを取得する良い方法はありますか?この使用例は、OutOfMemory エラーで突然死ぬのではなく、素敵なエラーメッセージ "あまりにも多くの人がこれを使用しているので、後でもう一度試してください" で新しい接続を拒否することによって、メモリ制限に近づいているときに優雅に失敗する Web サービスを持つことです。

これは、事前に各オブジェクトのコストを計算/推定することとは何の関係もないことに注意してください。原理的には、オブジェクトがどのくらいのメモリを消費するかを推定し、その推定値に基づいて新しい接続を拒否することができますが、これはちょっとハチャメチャで壊れやすいように思われます。

どのように解決するのですか?

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

EDIT: 私はもともとこのサンプルを提供しました (別のトピックでの 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());
  }
 }
}

ユーザーであるChristian Fries氏は、以下のように仮定するのは間違いであると指摘しています。 Runtime.getRuntime().freeMemory() がメモリ不足のエラーが発生するまでに割り当てられるメモリの量を示していると考えるのは間違いです。

から ドキュメント のシグネチャーの返り値は Runtime.getRuntime().freeMemory() はこのようなものです。

を返します。 将来割り当てられるオブジェクトのために現在利用可能なメモリの総量の概算をバイト数で表したもの。

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

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

とは allocatedMemory によって与えられる。

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

ここで重要なのは、空きメモリの概念との不一致です。ひとつは、オペレーティングシステムがJava仮想マシンに提供するメモリです。もうひとつは、Java Virtual Machine 自身が実際に使用しているメモリブロックのチャンクを構成するバイトの総量です。

Java アプリケーションに与えられたメモリが Java Virtual Machine によってブロック単位で管理されていることを考えると、このブロックの量は 空きメモリ の量は、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 がまだ生成される可能性があります。

結局のところ、使用する適切な方法は、アプリケーションの仕様に依存する程度が異なります。

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