Java obtenir de la mémoire disponible

Est-il un bon moyen d'obtenir le reste de la mémoire disponible pour la JVM au moment de l'exécution? Le cas d'utilisation de ce serait d'avoir des services web qui échouent gracieusement quand ils approchent de leurs limites de mémoire en refusant de nouvelles connexions avec un message d'erreur agréable "trop de personnes utilisant ceci, essayer à nouveau plus tard", plutôt que de mourir brusquement avec une erreur D'origine OutOfMemory.

Note Ceci n'a rien à voir avec le calcul/estimation préalable du coût de chaque objet. Dans principe je pourrais estimer combien de mémoire mes objets prennent et refusent de nouvelles connexions basées sur cette estimation, mais cela semble un peu hacky/fragile.

56
demandé sur Li Haoyi 2012-10-10 00:19:14

8 réponses

cet échantillon de William Brendel peut être utile.

EDIT: j'ai fourni à l'origine de cet échantillon (liaison de William Brendel sa réponse sur un autre sujet). Le créateur de ce thème (Steve M) voulait créer une application Java multi-plate-forme. Plus précisément, l'utilisateur essayait de trouver un moyen d'évaluer les ressources de la machine en cours d'exécution (espace disque, CPU et utilisation de la mémoire).

C'est un inline transcription de la réponse donnée à ce sujet. Toutefois, il a été souligné sur ce sujet que ce n'est pas la solution idéale, bien que ma réponse ait été marquée comme acceptée.

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

Utilisateur Chrétienne Frites souligne qu'il est faux de supposer que Runtime.getRuntime().freeMemory() vous donne la quantité de mémoire qui peut être alloué jusqu'à une erreur de mémoire se produit.

du documentation , la signature Runtime.getRuntime().freeMemory() est en tant que tel:

retourne: une approximation de la quantité totale de mémoire actuellement disponible pour les objets alloués futurs, mesurée en octets.

cependant, L'utilisateur Christian Fries affirme que cette fonction peut être mal interprétée. Il prétend que la quantité approximative de mémoire qui peut être attribuée jusqu'à ce qu'une erreur hors de la mémoire se produise (la mémoire libre) est susceptible d'être donnée par:

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

avec allocatedMemory étant donné par:

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

la clé ici est une divergence entre le concept de mémoire libre. Une chose est la mémoire que le système d'exploitation fournit la Machine virtuelle Java. Un autre est la quantité totale d'octets comprenant les morceaux de blocs de mémoire réellement utilisés par la Machine virtuelle Java elle-même.

considérant que la mémoire donnée aux applications Java est gérée en blocs par la machine virtuelle Java, la quantité de free memory disponible pour la Machine virtuelle Java peut ne pas correspondre exactement à la mémoire disponible pour une application Java.

plus précisément, Christian Fries indique l'utilisation des drapeaux -mx ou -Xmx pour définir la quantité maximale de mémoire disponible pour la Machine virtuelle Java. Il Note les différences de fonction suivantes:

/* 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 conclut sa réponse en disant que Runtime.getRuntime().freeMemory() renvoie en fait ce que l'on peut appeler de la mémoire libre présumable; même si une future allocation de mémoire ne dépasse pas la valeur retournée par cette fonction, si la Machine virtuelle Java N'a pas encore reçu le morceau de mémoire réel assigné par le système hôte, un "1519440920 java.lang.OutOfMemoryError peut encore être produit.

en fin de compte, la méthode appropriée à utiliser aura un degré variable de dépendance sur le spécificités de votre application.

je fournis un autre lien qui peut être utile. C'est une question posée par L'utilisateur Richard Dormand et répondu par stones333 sur la détermination de la taille Java tas par défaut utilisé.

69
répondu Blitzkoder 2017-05-23 12:03:05

Note: toutes les réponses jusqu'à présent, même celle acceptée, semblent répondre à la question en disant que Runtime.getRuntime().freeMemory() vous donne la quantité de mémoire qui peut être attribuée jusqu'à ce qu'une erreur hors de la mémoire se produit. Cependant: ce qui est faux.

Le approximative "de la 1519140920" quantité de mémoire qui peut être alloué jusqu'à une erreur de mémoire se produit, c'est à dire, la mémoire libre est de nature

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

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

explication: Si vous lancez la JVM via un paramètre-mx (ou-Xmx), vous spécifiez le montant maximum disponible pour la JVM. Runtime.getRuntime().maxMemory() vous donnera ce montant. A partir de cette quantité de mémoire système, le JVM attribuera la mémoire en morceaux, par exemple des blocs de 64 Mo. Au début, la JVM n'attribuera qu'une telle partie du système et non la totalité du montant. Runtime.getRuntime().totalMemory() donne la mémoire totale attribuée par le système, tandis que Runtime.getRuntime().freeMemory() vous donne la mémoire libre dans la mémoire totale allouée.

D'où:

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

est la mémoire libre déjà réservée par la JVM, mais il s'agit probablement d'une petite quantité. Et vous obtiendrez probablement presumableFreeMemory . Bien sûr, vous pouvez obtenir une exception hors de la mémoire même si vous avez essayé d'allouer un montant inférieur à presumableFreeMemory . Cela peut se produire si le JVM n'obtient pas le prochain morceau de mémoire du système. Cependant, sur la plupart des systèmes, cela ne se produira jamais et le système commencera plutôt à échanger - une situation que vous aimez éviter. W. r. T. à la question initiale: si-mx est fixé à une valeur raisonnable, alors presumableFreeMemory est un bon indicateur pour la mémoire libre.

55
répondu Christian Fries 2015-11-25 10:30:32

en plus d'utiliser les méthodes Runtime, vous pouvez obtenir des informations de mémoire supplémentaires en utilisant

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

Chaque MemoryUsage fournit init, utilisé, engagés et max des valeurs. Cela pourrait être utile si vous créez un thread de moniteur de mémoire qui interroge la mémoire et l'enregistre, vous fournissant une histoire de l'utilisation de la mémoire au fil du temps. Parfois, il est utile de voir l'utilisation de la mémoire au fil du temps menant aux erreurs.

si vous je veux vraiment aller à l'extrême, créer un fil de vidage en tas. Surveillez votre utilisation de la mémoire au fil du temps et quand elle dépasse certains seuils faites ce qui suit (cela fonctionne sur JBoss 5.0 - votre kilométrage peut varier):

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

plus tard, vous pouvez consulter ces fichiers de vidange tas avec l'eclipse analyseur de mémoire ou des outils similaires pour vérifier les fuites de mémoire, etc.

7
répondu Guido Simone 2012-10-09 23:11:03

en plus de l'autre réponse, je voudrais noter que faire cela n'est pas nécessairement une bonne idée, puisque vous pourriez avoir un cache dans votre application qui utilise SoftReferences .

un tel cache libérerait de la mémoire dès que le JVM atteindrait ses limites de mémoire. Attribuer de la mémoire, même s'il n'y a pas assez de mémoire libre, provoquerait d'abord la libération de la mémoire par les références douces, et la rendrait disponible pour l'allocation.

5
répondu JB Nizet 2012-10-09 20:25:22

pour obtenir la mémoire disponible à L'échelle du système D'exploitation, ajouter OSHI en utilisant la dépendance maven suivante:

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

puis en Java, utilisez le code suivant:

SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
long availableMemory = hal.getMemory().getAvailable();
5
répondu Oleksii Kyslytsyn 2018-06-28 21:26:25

Vous pouvez toujours appeler Runtime.getRuntime().freeMemory() .

L'autre moitié du problème, obtenir le coût d'objets, semble plus problématique pour moi.

je pense qu'une meilleure solution serait de comprendre comment regrouper et dimensionner vos services web afin qu'ils puissent accepter avec élégance 150% de la charge nominale sans nier de nouvelles connexions. On dirait qu'un exercice de dimensionnement te donnerait une meilleure solution qu'un piratage de code.

0
répondu duffymo 2012-10-09 20:21:27
long freeMemory = Runtime.getRuntime().freeMemory();
0
répondu Ryan Anderson 2012-10-09 20:22:38

Runtime.getRuntime().freeMemory() est un moyen d'obtenir mémoire libre pour JVM à ce moment pendant l'exécution. Est-ce la bonne façon (ou) non il dépend complètement de votre application.

0
répondu kosa 2013-04-24 14:05:36