54 votes

Est-ce que OpenJDK JVM restituera jamais de la mémoire de tas à Linux?

Nous avons une longue durée de vie des processus de serveur, que rarement besoin de beaucoup de RAM pour un court moment. Nous voyons qu'une fois que la JVM a obtenu la mémoire de l'OS, il ne retourne jamais en arrière de l'OS. Comment pouvons-nous demander à la JVM de retour de segment de mémoire pour le système d'exploitation?

Généralement, la accepté de répondre à de telles questions est d'utiliser -XX:MaxHeapFreeRatio et -XX:MinHeapFreeRatio. (Voir par ex. 1,2,3,4). Mais nous sommes en cours d'exécution java comme ceci:

java -Xmx4G -XX:MaxHeapFreeRatio=50 -XX:MinHeapFreeRatio=30 MemoryUsage

et encore le voir dans VisualVM:

Visual VM memory usage

Clairement, la JVM est de ne pas honorer -XX:MaxHeapFreeRatio=50 comme le heapFreeRatio est très proche de 100% et nulle part près de 50%. Aucun montant de cliquer sur "Effectuer GC" les retours de la mémoire pour le système d'exploitation.

MemoryUsage.java:

import java.util.ArrayList;
import java.util.List;

public class MemoryUsage {

    public static void main(String[] args) throws InterruptedException {
        System.out.println("Sleeping before allocating memory");
        Thread.sleep(10*1000);

        System.out.println("Allocating/growing memory");
        List<Long> list = new ArrayList<>();
        // Experimentally determined factor. This gives approximately 1750 MB
        // memory in our installation.
        long realGrowN = 166608000; //
        for (int i = 0 ; i < realGrowN ; i++) {
            list.add(23L);
        }

        System.out.println("Memory allocated/grown - sleeping before Garbage collecting");
        Thread.sleep(10*1000);

        list = null;
        System.gc();

        System.out.println("Garbage collected - sleeping forever");
        while (true) {
            Thread.sleep(1*1000);
        }
    }
}

Versions:

> java -version
openjdk version "1.8.0_66-internal"
OpenJDK Runtime Environment (build 1.8.0_66-internal-b01)
OpenJDK 64-Bit Server VM (build 25.66-b01, mixed mode)

> uname -a
Linux londo 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1+deb8u5 (2015-10-09) x86_64 GNU/Linux

> lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 8.2 (jessie)
Release:    8.2
Codename:   jessie

J'ai aussi essayé de OpenJDK 1.7 et Sun Java 1.8. Tous se comportent de la même manière et aucun donner de la mémoire au système d'exploitation.

Je ne pense que j'ai besoin et ce que le swap et la pagination ne sera pas "résoudre" ce, parce que les dépenses d'e / s disque sur la pagination près de 2 go de déchets à l'intérieur est juste un gaspillage de ressources. Si vous êtes en désaccord, merci de m'éclairer.

J'ai également écrit un petit memoryUsage.c avec malloc()/free(), et il n' retour de la mémoire pour le système d'exploitation. Il est possible en C. peut-être pas avec Java?

Edit: Augusto a souligné que la recherche aurait m'a conduit à l' -XX:MaxHeapFreeRatio et -XX:MinHeapFreeRatio seulement travaillé avec -XX:+UseSerialGC. J'étais fou de joie et il a essayé, intrigué par le fait que je n'avais pas trouvé moi-même. Oui, il a fait un travail avec mon MemoryUsage.java:

-XX:+UseSerialGC working with simple app

Cependant, lorsque j'ai essayé d' -XX:+UseSerialGC avec notre application réelle, pas tellement:

-XX:+UseSerialGC not working with real app

J'ai découvert que gc() après un certain temps, a l'aide, j'ai donc fait un thread qui n'a plus ou moins:

while (idle() && memoryTooLarge() && ! tooManyAttemptsYet()) {
    Thread.sleep(10*1000);
    System.gc();
}

et qui a fait le tour:

GC thread working

En fait, j'avais déjà vu le comportement avec -XX:+UseSerialGC et de multiples System.gc() des appels dans certains de mes nombreuses expériences, mais n'aimait pas la nécessité d'un GC fil. Et qui sait si ça va continuer à travailler comme notre application mobile et java évolue. Il doit y avoir une meilleure façon.

Quelle est la logique qui m'oblige à appeler System.gc() quatre fois (mais pas immédiatement), et où est ce genre de choses-ils documentés?

À la recherche de la documentation pour -XX:MaxHeapFreeRatio et -XX:MinHeapFreeRatio travaillant uniquement avec des -XX:+UseSerialGC, j'ai lu la documentation de l'outil java/exécutable et il n'est pas mentionné nulle part qu' -XX:MaxHeapFreeRatio et -XX:MinHeapFreeRatio ne fonctionne qu'avec des -XX:+UseSerialGC. En fait, la résolution d'un problème [JDK-8028391] Faire le Min/MaxHeapFreeRatio drapeaux gérable dit:

Afin de permettre aux applications de contrôler quand et comment pour permettre plus ou moins de GC, les drapeaux-XX:MinHeapFreeRatio et -XX:MaxHeapFreeRatio doit être faite gérable. Soutien pour ces indicateurs doivent également être mis en œuvre dans le par défaut parallèle collector.

Un commentaire pour la correction d'un problème dit:

Soutien pour ces indicateurs ont également été ajoutés à la ParallelGC comme le cadre de l'adaptation de la taille politique.

J'ai vérifié, et le correctif référencé dans la résolution d'un problème réalignés pour openjdk-8 est en effet contenue dans le paquet source archive pour la openjdk-8 version que j'utilise. Il devrait donc apparemment le travail en "par défaut parallèle collector", mais n'est pas, comme je l'ai démontré dans ce post. Je n'ai pas encore trouvé aucune documentation qui dit qu'elle doit fonctionner uniquement avec -XX:+UseSerialGC. Et comme je l'ai indiqué ici, même cela n'est pas fiable ou risquée.

Je ne peux pas juste obtenir -XX:MaxHeapFreeRatio et -XX:MinHeapFreeRatio à faire ce qu'ils promettent, sans avoir à passer par toutes ces paniers?

7voto

Sammy Lina Points 41

"G1 (-XX:+UseG1GC), Parallèle piéger (-XX:+UseParallelGC) et ParallelOld (-XX:+UseParallelOldGC) faire revenir la mémoire lorsque le tas se rétrécit. Je n'en suis pas sûre de Série et de la CMS, ils n'ont pas réduit leur entassement dans mes expériences.

Le parallèle collectionneurs avez besoin d'un nombre de tables avant de réduire le segment vers le bas à un niveau "acceptable" de la taille. C'est par la conception. Ils sont délibérément tenue sur le tas, à supposer qu'il sera nécessaire dans l'avenir. Le paramétrage de l'indicateur -XX:GCTimeRatio=1 permettra d'améliorer la situation quelque peu mais il faudra encore plusieurs GCs à se rétrécir beaucoup.

G1 est remarquablement bien à réduire le tas rapide, donc pour le cas d'utilisation décrit ci-dessus, je dirais que c'est résoluble par l'aide de G1 et en cours d'exécution System.gc() après avoir publié tous les caches et classe chargeurs etc."

http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6498735

0voto

pavan kumar Points 13

Si il y a la méthode (dire m1())qui ne le levage lourd dans votre application, vous pouvez essayer ceci:

  1. au lieu d'appeler la m1(), serialize tous les objets nécessaires pour la méthode de travail.
  2. créer une méthode main qui de-serialize les objets sérialisés dans l'étape précédente. et les appels m1() - cette méthode est point d'entrée pour un programme P1.
  3. À la fin de m1(), sérialiser la sortie pour le programme principal de sérialiser.
  4. exécuter P1 comme un programme distinct à l'aide de Runtime or ProcessBuilder.

De cette façon, lorsque le levage lourd méthode m1() se termine, le processus P1 prendra fin, ce qui devrait libérer le tas sur la JVM.

-2voto

Votre question est très complexe, je voudrais suggérer une facile solution. De ce que j'ai lu, vous savez comment coder en C et en Java. Peut-être à l'aide de la JNA (Java Native Access) ou JNI (Java Native Interface) pourrait résoudre la racine de la question (codage de la transformation lourde de la partie en C et l'appeler à partir de java). Une autre façon serait d'avoir un autre petit programme écrit en C faire le gros du travail - que vous appelez ce petit programme à partir de votre code java (de préférence dans son propre thread). Java Accès Natif Java Native Interface

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X