it-swarm.com.de

Java verfügbaren Speicher abrufen

Gibt es eine gute Möglichkeit, den verbleibenden Arbeitsspeicher zur Laufzeit für die JVM bereitzustellen? Der Anwendungsfall hierfür wäre, dass Webservices, die an ihre Speichergrenzen stoßen, ordnungsgemäß ausfallen, indem neue Verbindungen mit der Fehlermeldung "Zu viele Benutzer verwenden dies, versuchen es später erneut" abgelehnt werden, anstatt abrupt mit einem OutOfMemory-Fehler zu sterben .

Beachten Sie, dass dies nichts mit der vorherigen Berechnung/Schätzung der Kosten für jedes Objekt zu tun hat. Im Prinzip könnte ich anhand dieser Schätzung abschätzen, wie viel Speicher meine Objekte belegen und neue Verbindungen ablehnen, aber das scheint irgendwie hacky/fragil zu sein.

62
Li Haoyi

Dieses Beispiel von William Brendel kann von Nutzen sein.

BEARBEITEN: Ich habe dieses Beispiel ursprünglich bereitgestellt (Verknüpfung zu William Brendels Antwort zu einem anderen Thema). Der Ersteller dieses Themas (Steve M) wollte eine plattformübergreifende Java Anwendung erstellen. Insbesondere versuchte der Benutzer, ein Mittel zu finden, mit dem die Ressourcen des laufenden Computers (Festplattenspeicher, CPU- und Speichernutzung) bewertet werden können.

Dies ist eine Inline-Abschrift der Antwort in diesem Thema. Zu diesem Thema wurde jedoch darauf hingewiesen, dass es nicht die ideale Lösung ist, obwohl meine Antwort als akzeptiert markiert ist.

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());
  }
 }
}

Der Benutzer Christian Fries weist darauf hin, dass es falsch ist anzunehmen, dass Runtime.getRuntime().freeMemory() Ihnen die Speichermenge angibt, die zugewiesen werden kann, bis ein Fehler aufgrund von Speichermangel auftritt.

Aus der Dokumentation geht die Signaturrückgabe von Runtime.getRuntime().freeMemory() folgendermaßen hervor:

Returns: eine Annäherung an die Gesamtmenge des derzeit verfügbaren Speichers für zukünftige zugewiesene Objekte, gemessen in Bytes.

Der Benutzer Christian Fries behauptet jedoch, dass diese Funktion möglicherweise falsch interpretiert wird. Er behauptet, dass die ungefähre Menge an Speicher, die zugewiesen werden kann, bis ein Speicherfehler auftritt (der freie Speicher), wahrscheinlich gegeben ist durch:

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

Mit allocatedMemory gegeben durch:

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

Der Schlüssel ist hier eine Diskrepanz zwischen dem Konzept des freien Speichers. Eine Sache ist der Speicher, den das Betriebssystem der virtuellen Maschine Java zur Verfügung stellt. Eine andere ist die Gesamtmenge an Bytes, die die Blöcke von Speicherblöcken umfasst, die tatsächlich von der virtuellen Maschine Java selbst verwendet werden.

Wenn man bedenkt, dass der für Java - Anwendungen zur Verfügung gestellte Speicher in Blöcken von der Java - virtuellen Maschine verwaltet wird, kann die für die Java - virtuelle Maschine verfügbare Menge an freiem Speicher betragen stimmt nicht genau mit dem für eine Java - Anwendung verfügbaren Speicher überein.

Insbesondere bezeichnet Christian Fries die Verwendung der Flags -mx Oder -Xmx, Um die maximale Größe des für die virtuelle Maschine Java verfügbaren Arbeitsspeichers festzulegen. Er stellt folgende Funktionsunterschiede fest:

/* 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();

Christian schließt seine Antwort mit der Aussage, dass Runtime.getRuntime().freeMemory() tatsächlich das zurückgibt, was man als vermutliches freies Gedächtnis bezeichnen kann; Selbst wenn eine zukünftige Speicherzuweisung den von dieser Funktion zurückgegebenen Wert nicht überschreitet, hat die Java - virtuelle Maschine den vom Hostsystem zugewiesenen tatsächlichen Speicherbereich noch nicht erhalten. a Java.lang.OutOfMemoryError kann noch produziert werden.

Letztendlich hängt die richtige Methode in unterschiedlichem Maße von den Besonderheiten Ihrer Anwendung ab.

Ich stelle einen anderen Link zur Verfügung, der nützlich sein kann. Diese Frage wurde vom Benutzer Richard Dormand gestellt und von stones333 beantwortet, um die verwendete Standard-Heap-Größe Java zu bestimmen.

77
Blitzkoder

Hinweis: Alle bisherigen Antworten, auch die akzeptierten, scheinen die Frage zu beantworten, indem sie besagen, dass Runtime.getRuntime().freeMemory() Ihnen die Speichermenge angibt, die zugewiesen werden kann, bis ein Fehler aufgrund unzureichenden Speichers auftritt. Dies ist jedoch falsch.

Die ngefähre Speicherkapazität, die zugewiesen werden kann, bis ein Speicherfehler auftritt, d. H. Der freie Speicher ist wahrscheinlich

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

woher

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

Erläuterung: Wenn Sie die JVM über einen -mx-Parameter (oder -Xmx) starten, geben Sie die maximale Menge an, die der JVM zur Verfügung steht. Runtime.getRuntime().maxMemory() gibt Ihnen diesen Betrag. Aus dieser Menge an Systemspeicher reserviert die JVM Speicher in Blöcken, beispielsweise in Blöcken von 64 MB. Zu Beginn weist die JVM nur einen solchen Teil des Systems und nicht den vollen Betrag zu. Runtime.getRuntime().totalMemory() gibt den gesamten vom System zugewiesenen Speicher an, während Runtime.getRuntime().freeMemory() den freien Speicher angibt innerhalb den gesamten zugewiesenen Speicher.

Daher:

long definitelyFreeMemory = Runtime.getRuntime().freeMemory();

ist der freie Speicher, der bereits von der JVM reserviert wurde, aber wahrscheinlich nur eine kleine Menge. Und Sie werden wahrscheinlich presumableFreeMemory bekommen. Natürlich kann es vorkommen, dass Ihnen der Speicherplatz ausgeht, auch wenn Sie versucht haben, einen Wert zuzuweisen, der kleiner als presumableFreeMemory ist. Dies kann passieren, wenn die JVM nicht den nächsten Speicherblock vom System erhält. Auf den meisten Systemen wird dies jedoch niemals passieren und das System wird eher mit dem Tauschen beginnen - eine Situation, die Sie gerne vermeiden möchten. W.r.t. zur ursprünglichen frage: wenn -mx auf einen vernünftigen wert gesetzt ist, dann ist presumableFreeMemory ein guter indikator für den freien speicher.

62
Christian Fries

Zusätzlich zur Verwendung der Runtime-Methoden können Sie mit einige zusätzliche Speicherinformationen abrufen

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

Jedes MemoryUsage liefert die Werte init, used, commit und max. Dies kann hilfreich sein, wenn Sie einen Speicherüberwachungs-Thread erstellen, der den Speicher abfragt und protokolliert und Ihnen einen Verlauf der Speichernutzung im Laufe der Zeit liefert. Manchmal ist es hilfreich, die Speichernutzung im Laufe der Zeit zu beobachten, die zu den Fehlern geführt hat.

Wenn Sie das wirklich auf die Spitze treiben möchten, erstellen Sie einen Heap-Dump-Thread. Überwachen Sie die Speichernutzung im Laufe der Zeit und gehen Sie wie folgt vor, wenn bestimmte Schwellenwerte überschritten werden (dies funktioniert mit JBoss 5.0 - Ihre Laufleistung kann variieren):

// 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);

Später können Sie diese Heap-Dump-Dateien mit Eclipse Memory Analyzer oder ähnlichen Tools überprüfen, um nach Speicherlecks zu suchen.

7
Guido Simone

Zusätzlich zur anderen Antwort möchte ich darauf hinweisen, dass dies nicht unbedingt eine gute Idee ist, da Ihre App möglicherweise einen Cache enthält, der SoftReferences verwendet.

Ein solcher Cache würde Speicher freigeben, sobald die JVM ihre Speichergrenzen erreicht. Das Zuweisen von Speicher, auch wenn nicht genügend freier Speicher vorhanden ist, würde zuerst dazu führen, dass Speicher von den Softreferenzen freigegeben wird und für die Zuordnung verfügbar gemacht wird.

5
JB Nizet

Fügen Sie OSHI hinzu, um den für das gesamte Betriebssystem verfügbaren Speicher zu erhalten, indem Sie die folgende Maven-Abhängigkeit verwenden:

<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>LATEST</version>
</dependency>

Verwenden Sie dann in Java den folgenden Code:

SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
long availableMemory = hal.getMemory().getAvailable();
5

Sie können immer Runtime.getRuntime().freeMemory() aufrufen.

Die andere Hälfte des Problems, die Kosten für Objekte zu ermitteln, erscheint mir problematischer.

Ich denke, eine bessere Lösung wäre, herauszufinden, wie Sie Ihre Web-Services in Clustern zusammenfassen und skalieren können, damit sie problemlos 150% der Nennlast akzeptieren können, ohne neue Verbindungen zu verweigern. Hört sich an, als ob Sie mit einer Größenanpassung eine bessere Lösung als mit einem Code-Hack erhalten würden.

0
duffymo

Runtime.getRuntime().freeMemory() ist eine Möglichkeit, freien Speicher für JVM zu diesem Zeitpunkt während der Laufzeit abzurufen. Ob es gut ist (oder nicht), hängt ganz von Ihrer Anwendung ab.

0
kosa
long freeMemory = Runtime.getRuntime().freeMemory();
0
Ryan Anderson