Czym są Runtime.getRuntime (). TotalMemory () i freeMemory ()?


Odpowiedzi:


195

Zgodnie z API

totalMemory()

Zwraca całkowitą ilość pamięci w wirtualnej maszynie Java. Wartość zwracana przez tę metodę może się zmieniać w czasie, w zależności od środowiska hosta. Należy zauważyć, że ilość pamięci wymagana do przechowywania obiektu dowolnego typu może być zależna od implementacji.

maxMemory()

Zwraca maksymalną ilość pamięci, której będzie próbowała użyć wirtualna maszyna Java. Jeśli nie ma wewnętrznego limitu, zostanie zwrócona wartość Long.MAX_VALUE.

freeMemory()

Zwraca ilość wolnej pamięci w wirtualnej maszynie języka Java. Wywołanie metody gc może spowodować zwiększenie wartości zwracanej przez freeMemory.

W odniesieniu do twojego pytania maxMemory()zwraca -Xmxwartość.

Możesz się zastanawiać, dlaczego istnieje totalMemory () ORAZ maxMemory () . Odpowiedź brzmi, że maszyna JVM leniwie przydziela pamięć. Powiedzmy, że zaczynasz proces Java w ten sposób:

java -Xms64m -Xmx1024m Foo

Twój proces zaczyna się od 64 MB pamięci, a jeśli i kiedy potrzebuje więcej (do 1024 m), przydzieli pamięć. totalMemory()odpowiada ilości pamięci aktualnie dostępnej dla maszyny JVM dla Foo. Jeśli JVM potrzebuje więcej pamięci, to leniwie przeznaczyć go do maksymalnej pamięci. Jeśli będziesz biegać -Xms1024m -Xmx1024m, wartość, którą uzyskasz totalMemory()i maxMemory()będzie równa.

Ponadto, jeśli chcesz dokładnie obliczyć ilość używanej pamięci, wykonaj to za pomocą następującego obliczenia:

final long usedMem = totalMemory() - freeMemory();

-XmxWartość wydaje się mieć bezpośredni wpływ na początkową maxMemory()wartość jednak widziałem raportowany maxMemory()wzrost o małej ilości, może ~ 1%, podczas gdy program jest uruchomiony.
H2ONaCl

2
Czym się to różni od Debug.getNativeHeapFreeSize()?
IgorGanapolsky

@ H2ONaCl tak, może się nieznacznie zmienić, ponieważ maszyny JVM UseAdaptiveSizePolicysą domyślnie włączone. A przy okazji: maxMemory()= Xmx- rozmiar pojedynczej przestrzeni ocalałej. Czemu? Ponieważ w tym samym czasie można wykorzystać tylko jedno miejsce na ocalałego.
G. Demecki

236

Nazwy i wartości są mylące. Jeśli szukasz całkowitej wolnej pamięci , będziesz musiał samodzielnie obliczyć tę wartość. To nie jest to, z czego otrzymujesz freeMemory();.

Zobacz poniższy przewodnik:

Całkowita wyznaczona pamięć , będzie równa skonfigurowanej wartości -Xmx :

Runtime.getRuntime (). MaxMemory ();

Aktualnie przydzielona wolna pamięć to aktualnie przydzielone miejsce gotowe na nowe obiekty. Uwaga, to nie jest całkowita ilość wolnej dostępnej pamięci:

Runtime.getRuntime (). FreeMemory ();

Całkowita przydzielona pamięć , to całkowita przydzielona przestrzeń zarezerwowana dla procesu Java:

Runtime.getRuntime (). TotalMemory ();

Wykorzystaną pamięć należy obliczyć:

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

Należy obliczyć całkowitą ilość wolnej pamięci :

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

Zdjęcie może pomóc wyjaśnić:

pamięć wykonawcza java


1
Czy to się różni od Debug.getMemoryInfo()?
IgorGanapolsky

1
Uwaga: Używana pamięć może zawierać obiekty , do których nie istnieją już odniesienia, które zostaną zmiecione przez następny GC.
Gab 是 好人

@cheneym, wolna i nielokalizowana pamięć zostanie zajęta, ponieważ instrukcje kodu bajtowego java będą przetwarzane przez procesor tylko wtedy, gdy "Xmx - Usedmemory" jest dostępne w komputerze. Xmx jest jak maksymalna pojemność balonu, który mógłby wypełnić się powietrzem wydostającym się z powietrza w samej maszynie, jak tylko dostanie się powietrze, zostanie napełniony i wybuchnie, gdy przekroczy limit Xmx. Ale całkowita pamięć wolna nie poda rzeczywistej pamięci avbl w maszynie dla JVM, ale tylko nmbr. Czy istnieje jakikolwiek sposób, żebym mógł znaleźć rzeczywistą pamięć avlbl w komputerze, abym mógł dowiedzieć się, czy pamięć rqd jest avlbl, czy nie dla remaningu JVM proces ?
Maria

12

Aby lepiej to zrozumieć, uruchom następujący program (w jdk1.7.x):

$ java -Xms1025k -Xmx1025k -XshowSettings:vm  MemoryTest

Spowoduje to wydrukowanie opcji jvm oraz używanej , wolnej , całkowitej i maksymalnej pamięci dostępnej w jvm.

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

8

Skodyfikowana wersja wszystkich innych odpowiedzi (w momencie pisania):

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

7

Runtime # totalMemory - pamięć przydzielona do tej pory przez maszynę JVM. To niekoniecznie jest w użyciu lub maksimum.

Runtime # maxMemory - maksymalna ilość pamięci, do której wykorzystania została skonfigurowana maszyna JVM. Gdy proces osiągnie tę kwotę, JVM nie przydzieli więcej, a zamiast tego GC znacznie częściej.

Runtime # freeMemory - nie jestem pewien, czy jest to mierzone na podstawie maksimum, czy części sumy, która jest niewykorzystana. Domyślam się, że jest to miara części całości, która jest niewykorzystana.


5

Rozmiar sterty maszyny JVM można zwiększać i zmniejszać za pomocą mechanizmu zbierania elementów bezużytecznych. Ale nie może przydzielić więcej niż maksymalny rozmiar pamięci: Runtime.maxMemory. To jest znaczenie maksymalnej pamięci. Całkowita pamięć oznacza przydzielony rozmiar sterty. Wolna pamięć oznacza dostępny rozmiar w całkowitej pamięci.

przykład) java -Xms20M -Xmn10M -Xmx50M ~~~. Oznacza to, że jvm powinno przydzielać stertę 20 MB na starcie (ms). W tym przypadku całkowita pamięć wynosi 20 MB. wolna pamięć zajmuje 20 MB. Jeśli potrzeba więcej sterty, JVM przydzieli więcej, ale nie może przekroczyć 50 M (mx). W przypadku maksymalnego, całkowita pamięć to 50 MB, a wolny rozmiar to 50 MB. Jeśli chodzi o minimalny rozmiar (mn), jeśli sterta nie jest używana zbyt często, jvm może zmniejszyć rozmiar sterty do 10 MB.

Ten mechanizm służy wydajności pamięci. Jeśli mały program java działa na ogromnej pamięci sterty o stałym rozmiarze, tak dużo pamięci może być marnotrawstwem.


1

Wyniki można zobaczyć w formacie MB , z podziałem 1024 x 1024, co odpowiada 1 MB .

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");  
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.