¿Qué son Runtime.getRuntime (). TotalMemory () y freeMemory ()?

Respuestas:

195

De acuerdo con la API

totalMemory()

Devuelve la cantidad total de memoria en la máquina virtual Java. El valor devuelto por este método puede variar con el tiempo, según el entorno del host. Tenga en cuenta que la cantidad de memoria requerida para contener un objeto de cualquier tipo puede depender de la implementación.

maxMemory()

Devuelve la cantidad máxima de memoria que la máquina virtual Java intentará usar. Si no hay un límite inherente, se devolverá el valor Long.MAX_VALUE.

freeMemory()

Devuelve la cantidad de memoria libre en la máquina virtual Java. Llamar al método gc puede aumentar el valor devuelto por freeMemory.

En referencia a su pregunta, maxMemory()devuelve el -Xmxvalor.

Quizás se pregunte por qué hay un totalMemory () Y un maxMemory () . La respuesta es que la JVM asigna memoria perezosamente. Digamos que comienzas tu proceso Java como tal:

java -Xms64m -Xmx1024m Foo

Su proceso comienza con 64 MB de memoria, y si necesita más (hasta 1024 m), asignará memoria. totalMemory()corresponde a la cantidad de memoria actualmente disponible para JVM para Foo. Si la JVM necesita más memoria, la asignará perezosamente hasta la memoria máxima. Si corre con -Xms1024m -Xmx1024m, el valor que obtiene totalMemory()y maxMemory()será igual.

Además, si desea calcular con precisión la cantidad de memoria utilizada , hágalo con el siguiente cálculo:

final long usedMem = totalMemory() - freeMemory();
Amir Afghani
fuente
El -Xmxvalor parece afectar directamente el maxMemory()valor inicial , sin embargo, he visto el maxMemory()aumento reportado en una pequeña cantidad, tal vez ~ 1%, mientras se ejecuta el programa.
H2ONaCl
2
¿Cómo es esto diferente de Debug.getNativeHeapFreeSize()?
IgorGanapolsky
@ H2ONaCl sí, podría cambiar ligeramente, porque JVM UseAdaptiveSizePolicyestá habilitado de forma predeterminada. Y por cierto: maxMemory()= Xmx- tamaño de un solo espacio de sobreviviente. ¿Por qué? Porque al mismo tiempo, solo se puede usar un espacio de sobreviviente.
G. Demecki
236

Los nombres y valores son confusos. Si está buscando la memoria libre total , tendrá que calcular este valor usted mismo. No es de lo que obtienes freeMemory();.

Ver la siguiente guía:

Memoria designada total , esto será igual al valor configurado -Xmx :

Runtime.getRuntime (). MaxMemory ();

Memoria libre asignada actual , es el espacio asignado actual listo para nuevos objetos. Cuidado, esta no es la memoria total disponible libre :

Runtime.getRuntime (). FreeMemory ();

Memoria asignada total , es el espacio asignado total reservado para el proceso de Java:

Runtime.getRuntime (). TotalMemory ();

Memoria usada , debe calcularse:

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

Memoria libre total , debe calcularse:

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

Una imagen puede ayudar a aclarar:

memoria de tiempo de ejecución de Java

cheneym
fuente
1
¿Es esto diferente de Debug.getMemoryInfo()?
IgorGanapolsky
1
Nota: La memoria usada puede contener objetos que ya no están referenciados y que serán barridos por el próximo GC.
Gab 是 好人
@cheneym, la memoria libre y no ubicada se ocupará ya que las instrucciones del código de bytes de Java serán procesadas por el procesador solo si "Xmx - Usedmemory" está disponible en la máquina. Xmx es como la capacidad máxima de globo que podría llenarse con aire que sale del aire de la máquina, tan pronto como reciba aire, se llenará y explotará una vez que exceda el límite de Xmx. Pero freememory total no indicará la memoria avbl real en la máquina para JVM, pero solo el número está allí. De alguna manera podría averiguar la memoria avlbl real en la máquina para poder saber si la memoria rqd es avlbl o no para la remanidación de JVM proceso?
Maria
12

Para entenderlo mejor, ejecute este siguiente programa (en jdk1.7.x):

$ java -Xms1025k -Xmx1025k -XshowSettings:vm  MemoryTest

Esto imprimirá las opciones de jvm y la memoria usada , libre , total y máxima disponible en 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");            
        }
}
Sriram
fuente
8

Versión codificada de todas las demás respuestas (en el momento de la redacción):

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
fuente
7

Runtime # totalMemory : la memoria que la JVM ha asignado hasta ahora. Esto no es necesariamente lo que está en uso o el máximo.

Tiempo de ejecución # maxMemory : la cantidad máxima de memoria que la JVM se ha configurado para usar. Una vez que su proceso alcance esta cantidad, la JVM no asignará más y, en cambio, GC, con mucha más frecuencia.

Runtime # freeMemory : no estoy seguro de si esto se mide a partir del máximo o la parte del total que no se utiliza. Supongo que es una medida de la porción del total que no se usa.

Tim Bender
fuente
5

El tamaño de almacenamiento dinámico de JVM puede crecer y reducirse mediante el mecanismo de recolección de basura. Pero no puede asignar más del tamaño máximo de memoria: Runtime.maxMemory. Este es el significado de la memoria máxima. Memoria total significa el tamaño de almacenamiento dinámico asignado. Y memoria libre significa el tamaño disponible en la memoria total.

ejemplo) java -Xms20M -Xmn10M -Xmx50M ~~~. Esto significa que jvm debería asignar el montón 20M en el inicio (ms). En este caso, la memoria total es de 20M. la memoria libre tiene un tamaño de 20M. Si se necesita más almacenamiento dinámico, JVM asigna más pero no puede superar los 50M (mx). En el caso del máximo, la memoria total es de 50M, y el tamaño libre es de 50M. En cuanto al tamaño mínimo (mn), si el montón no se usa mucho, jvm puede reducir el tamaño del montón a 10M.

Este mecanismo es para la eficiencia de la memoria. Si un pequeño programa de Java se ejecuta en una gran memoria de almacenamiento dinámico de tamaño fijo, puede desperdiciar tanta memoria.

ALAM-Kim
fuente
1

Puede ver los resultados en formato MB , con la división de 1024 x 1024, que es igual a 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");  
Gabriel Gabriel López
fuente