Was sind Runtime.getRuntime (). TotalMemory () und freeMemory ()?

Antworten:

195

Laut API

totalMemory()

Gibt die Gesamtspeichermenge in der Java Virtual Machine zurück. Der von dieser Methode zurückgegebene Wert kann je nach Hostumgebung im Laufe der Zeit variieren. Beachten Sie, dass die zum Speichern eines Objekts eines bestimmten Typs erforderliche Speichermenge möglicherweise implementierungsabhängig ist.

maxMemory()

Gibt die maximale Speichermenge zurück, die die virtuelle Java-Maschine zu verwenden versucht. Wenn es keine inhärente Grenze gibt, wird der Wert Long.MAX_VALUE zurückgegeben.

freeMemory()

Gibt die Menge an freiem Speicher in der Java Virtual Machine zurück. Das Aufrufen der gc-Methode kann dazu führen, dass der von freeMemory zurückgegebene Wert erhöht wird.

Gibt in Bezug auf Ihre Frage maxMemory()den -XmxWert zurück.

Sie fragen sich vielleicht, warum es ein totalMemory () UND ein maxMemory () gibt . Die Antwort ist, dass die JVM den Speicher träge zuweist. Nehmen wir an, Sie starten Ihren Java-Prozess als solchen:

java -Xms64m -Xmx1024m Foo

Ihr Prozess beginnt mit 64 MB Arbeitsspeicher. Wenn mehr Speicher benötigt wird (bis zu 1024 MB), wird Speicher zugewiesen. totalMemory()entspricht der Speichermenge , die der JVM für Foo derzeit zur Verfügung steht. Wenn die JVM mehr Speicher benötigt, wird es träge zuteilen bis zur maximalen Speicher. Wenn Sie mit laufen -Xms1024m -Xmx1024m, aus dem Wert , den Sie erhalten totalMemory()und maxMemory()wird gleich sein.

Wenn Sie die Menge des verwendeten Speichers genau berechnen möchten , tun Sie dies mit der folgenden Berechnung:

final long usedMem = totalMemory() - freeMemory();
Amir Afghani
quelle
Der -XmxWert scheint sich direkt auf den Anfangswert auszuwirken maxMemory(), aber ich habe gesehen, dass der gemeldete maxMemory()Anstieg um einen kleinen Betrag, vielleicht ~ 1%, während das Programm ausgeführt wird.
H2ONaCl
2
Wie unterscheidet sich das von Debug.getNativeHeapFreeSize()?
IgorGanapolsky
@ H2ONaCl ja, es kann sich geringfügig ändern, da JVMs UseAdaptiveSizePolicystandardmäßig aktiviert sind. Und übrigens: maxMemory()= Xmx- Größe eines einzelnen Überlebensraums. Warum? Denn gleichzeitig kann nur ein Überlebensraum genutzt werden.
G. Demecki
236

Die Namen und Werte sind verwirrend. Wenn Sie nach dem gesamten freien Speicher suchen, müssen Sie diesen Wert selbst berechnen. Es ist nicht das, wovon du kommst freeMemory();.

Siehe folgende Anleitung:

Der gesamte angegebene Speicher entspricht dem konfigurierten -Xmx- Wert:

Runtime.getRuntime (). MaxMemory ();

Der aktuell zugewiesene freie Speicher ist der aktuell zugewiesene Speicherplatz , der für neue Objekte bereit ist . Achtung, dies ist nicht der gesamte frei verfügbare Speicher:

Runtime.getRuntime (). FreeMemory ();

Der insgesamt zugewiesene Speicher ist der insgesamt zugewiesene Speicherplatz, der für den Java-Prozess reserviert ist:

Runtime.getRuntime (). TotalMemory ();

Verwendeter Speicher muss berechnet werden:

usedMemory = Runtime.getRuntime (). totalMemory () - Runtime.getRuntime (). freeMemory ();

Der gesamte freie Speicher muss berechnet werden:

freeMemory = Runtime.getRuntime (). maxMemory () - usedMemory;

Ein Bild kann helfen, Folgendes zu verdeutlichen:

Java-Laufzeitspeicher

Chenym
quelle
1
Ist das anders als Debug.getMemoryInfo()?
IgorGanapolsky
1
Hinweis: Der verwendete Speicher enthält möglicherweise keine referenzierten Objekte mehr, die vom nächsten GC entfernt werden.
Gab
@cheneym, freier und nicht lokalisierter Speicher wird belegt, da die Java-Bytecode-Anweisungen vom Prozessor nur verarbeitet werden, wenn "Xmx - Usedmemory" in der Maschine verfügbar ist. Xmx ist wie die maximale Kapazität eines Ballons, der sich mit Luft füllen kann, die aus der Luft in der Maschine selbst austritt. Sobald Luft entsteht, wird sie gefüllt und explodiert, sobald die Xmx-Grenze überschritten wird. Aber total freememory sagt nicht den tatsächlichen avbl-Speicher in der Maschine für JVM, sondern nur den nmbr. Gibt es eine Möglichkeit, den tatsächlichen avlbl-Speicher in der Maschine herauszufinden, damit ich herausfinden kann, ob der rqd-Speicher für JVM-Remaning verfügbar ist oder nicht Prozess ?
Maria
12

Führen Sie zum besseren Verständnis das folgende Programm aus (in jdk1.7.x):

$ java -Xms1025k -Xmx1025k -XshowSettings:vm  MemoryTest

Dadurch werden die JVM- Optionen und der verwendete , freie , vollständige und maximale in JVM verfügbare Speicher gedruckt.

public class MemoryTest {    
    public static void main(String args[]) {
                System.out.println("Used Memory   :  " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) + " bytes");
                System.out.println("Free Memory   : " + Runtime.getRuntime().freeMemory() + " bytes");
                System.out.println("Total Memory  : " + Runtime.getRuntime().totalMemory() + " bytes");
                System.out.println("Max Memory    : " + Runtime.getRuntime().maxMemory() + " bytes");            
        }
}
Sriram
quelle
8

Kodifizierte Version aller anderen Antworten (zum Zeitpunkt des Schreibens):

import java.io.*;

/**
 * This class is based on <a href="http://stackoverflow.com/users/2478930/cheneym">cheneym</a>'s
 * <a href="http://stackoverflow.com/a/18375641/253468">awesome interpretation</a>
 * of the Java {@link Runtime}'s memory query methods, which reflects intuitive thinking.
 * Also includes comments and observations from others on the same question, and my own experience.
 * <p>
 * <img src="https://i.stack.imgur.com/GjuwM.png" alt="Runtime's memory interpretation">
 * <p>
 * <b>JVM memory management crash course</b>:
 * Java virtual machine process' heap size is bounded by the maximum memory allowed.
 * The startup and maximum size can be configured by JVM arguments.
 * JVMs don't allocate the maximum memory on startup as the program running may never require that.
 * This is to be a good player and not waste system resources unnecessarily.
 * Instead they allocate some memory and then grow when new allocations require it.
 * The garbage collector will be run at times to clean up unused objects to prevent this growing.
 * Many parameters of this management such as when to grow/shrink or which GC to use
 * can be tuned via advanced configuration parameters on JVM startup.
 *
 * @see <a href="http://stackoverflow.com/a/42567450/253468">
 *     What are Runtime.getRuntime().totalMemory() and freeMemory()?</a>
 * @see <a href="http://www.oracle.com/technetwork/java/javase/memorymanagement-whitepaper-150215.pdf">
 *     Memory Management in the Sun Java HotSpot™ Virtual Machine</a>
 * @see <a href="http://docs.oracle.com/javase/8/docs/technotes/tools/windows/java.html">
 *     Full VM options reference for Windows</a>
 * @see <a href="http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html">
 *     Full VM options reference for Linux, Mac OS X and Solaris</a>
 * @see <a href="http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html">
 *     Java HotSpot VM Options quick reference</a>
 */
public class SystemMemory {

    // can be white-box mocked for testing
    private final Runtime runtime = Runtime.getRuntime();

    /**
     * <b>Total allocated memory</b>: space currently reserved for the JVM heap within the process.
     * <p>
     * <i>Caution</i>: this is not the total memory, the JVM may grow the heap for new allocations.
     */
    public long getAllocatedTotal() {
        return runtime.totalMemory();
    }

    /**
     * <b>Current allocated free memory</b>: space immediately ready for new objects.
     * <p>
     * <i>Caution</i>: this is not the total free available memory,
     * the JVM may grow the heap for new allocations.
     */
    public long getAllocatedFree() {
        return runtime.freeMemory();
    }

    /**
     * <b>Used memory</b>:
     * Java heap currently used by instantiated objects. 
     * <p>
     * <i>Caution</i>: May include no longer referenced objects, soft references, etc.
     * that will be swept away by the next garbage collection.
     */
    public long getUsed() {
        return getAllocatedTotal() - getAllocatedFree();
    }

    /**
     * <b>Maximum allocation</b>: the process' allocated memory will not grow any further.
     * <p>
     * <i>Caution</i>: This may change over time, do not cache it!
     * There are some JVMs / garbage collectors that can shrink the allocated process memory.
     * <p>
     * <i>Caution</i>: If this is true, the JVM will likely run GC more often.
     */
    public boolean isAtMaximumAllocation() {
        return getAllocatedTotal() == getTotal();
        // = return getUnallocated() == 0;
    }

    /**
     * <b>Unallocated memory</b>: amount of space the process' heap can grow.
     */
    public long getUnallocated() {
        return getTotal() - getAllocatedTotal();
    }

    /**
     * <b>Total designated memory</b>: this will equal the configured {@code -Xmx} value.
     * <p>
     * <i>Caution</i>: You can never allocate more memory than this, unless you use native code.
     */
    public long getTotal() {
        return runtime.maxMemory();
    }

    /**
     * <b>Total free memory</b>: memory available for new Objects,
     * even at the cost of growing the allocated memory of the process.
     */
    public long getFree() {
        return getTotal() - getUsed();
        // = return getAllocatedFree() + getUnallocated();
    }

    /**
     * <b>Unbounded memory</b>: there is no inherent limit on free memory.
     */
    public boolean isBounded() {
        return getTotal() != Long.MAX_VALUE;
    }

    /**
     * Dump of the current state for debugging or understanding the memory divisions.
     * <p>
     * <i>Caution</i>: Numbers may not match up exactly as state may change during the call.
     */
    public String getCurrentStats() {
        StringWriter backing = new StringWriter();
        PrintWriter out = new PrintWriter(backing, false);
        out.printf("Total: allocated %,d (%.1f%%) out of possible %,d; %s, %s %,d%n",
                getAllocatedTotal(),
                (float)getAllocatedTotal() / (float)getTotal() * 100,
                getTotal(),
                isBounded()? "bounded" : "unbounded",
                isAtMaximumAllocation()? "maxed out" : "can grow",
                getUnallocated()
        );
        out.printf("Used: %,d; %.1f%% of total (%,d); %.1f%% of allocated (%,d)%n",
                getUsed(),
                (float)getUsed() / (float)getTotal() * 100,
                getTotal(),
                (float)getUsed() / (float)getAllocatedTotal() * 100,
                getAllocatedTotal()
        );
        out.printf("Free: %,d (%.1f%%) out of %,d total; %,d (%.1f%%) out of %,d allocated%n",
                getFree(),
                (float)getFree() / (float)getTotal() * 100,
                getTotal(),
                getAllocatedFree(),
                (float)getAllocatedFree() / (float)getAllocatedTotal() * 100,
                getAllocatedTotal()
        );
        out.flush();
        return backing.toString();
    }

    public static void main(String... args) {
        SystemMemory memory = new SystemMemory();
        System.out.println(memory.getCurrentStats());
    }
}
TWiStErRob
quelle
7

Runtime # totalMemory - der Speicher, den die JVM bisher zugewiesen hat. Dies ist nicht unbedingt das, was verwendet wird oder das Maximum.

Runtime # maxMemory - Die maximale Speichermenge, für die die JVM konfiguriert wurde. Sobald Ihr Prozess diesen Betrag erreicht hat, wird die JVM nicht mehr und stattdessen viel häufiger GC zuweisen.

Runtime # freeMemory - Ich bin nicht sicher, ob dies anhand des Maximums oder des Teils der Summe gemessen wird, der nicht verwendet wird. Ich vermute, es ist ein Maß für den Anteil der Gesamtmenge, der nicht verwendet wird.

Tim Bender
quelle
5

Die Größe des JVM-Heapspeichers kann durch den Garbage-Collection-Mechanismus vergrößert und verkleinert werden. Es kann jedoch keine maximale Speichergröße zugewiesen werden: Runtime.maxMemory. Dies ist die Bedeutung des maximalen Speichers. Gesamtspeicher bedeutet die zugewiesene Heap-Größe. Und freier Speicher bedeutet die verfügbare Größe im Gesamtspeicher.

Beispiel) Java -Xms20M -Xmn10M -Xmx50M ~~~. Dies bedeutet, dass jvm beim Start (ms) Heap 20M zuweisen sollte. In diesem Fall beträgt der Gesamtspeicher 20 MB. Der freie Speicher hat eine Größe von 20 Millionen. Wenn mehr Heap benötigt wird, weist JVM mehr zu, kann jedoch nicht mehr als 50 MB (mx) zuweisen. Im Falle eines Maximums beträgt der Gesamtspeicher 50 MB und die freie Größe 50 MB. Was die Mindestgröße (mn) betrifft, kann jvm die Heap-Größe auf 10 MB verkleinern, wenn der Heap nicht häufig verwendet wird.

Dieser Mechanismus dient der Effizienz des Speichers. Wenn kleine Java-Programme auf einem großen Heap-Speicher mit fester Größe ausgeführt werden, kann so viel Speicher verschwenderisch sein.

ALam-Kim
quelle
1

Sie können die Ergebnisse im MB-Format mit einer Teilung von 1024 x 1024 anzeigen, was 1 MB entspricht .

int dataSize = 1024 * 1024;

System.out.println("Used Memory   : " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/dataSize + " MB");
System.out.println("Free Memory   : " + Runtime.getRuntime().freeMemory()/dataSize + " MB");
System.out.println("Total Memory  : " + Runtime.getRuntime().totalMemory()/dataSize + " MB");
System.out.println("Max Memory    : " + Runtime.getRuntime().maxMemory()/dataSize + " MB");  
GAbriel lopez
quelle