web-dev-qa-db-fra.com

Java utilisant beaucoup plus de mémoire que celle allouée avec -Xmx

J'ai un projet que j'écris (en Java) pour une classe où le prof dit que nous ne sommes pas autorisés à utiliser plus de 200m Je limite la mémoire de la pile à 50m (juste pour être absolument sûr) avec -Xmx50m mais selon top , il utilise toujours 300m

J'ai essayé de lancer Eclipse Memory Analyzer et il ne rapporte que 26m

Est-ce que tout cela peut être de la mémoire sur la pile?, Je suis sûr que je ne vais jamais plus loin qu'environ 300 appels de méthode en profondeur (oui, c'est une recherche DFS récursive), donc cela devrait signifier que chaque trame de pile utilise presque un mégaoctet qui semble difficile à croire.

Le programme est monothread. Quelqu'un connaît-il d'autres endroits où je pourrais réduire l'utilisation de la mémoire? De plus, comment puis-je vérifier/limiter la quantité de mémoire utilisée par la pile?

MISE À JOUR: J'utilise maintenant les options JVM suivantes sans effet (toujours environ 300m selon le haut): -Xss104k -Xms40m -Xmx40m -XX:MaxPermSize=1k

Une autre MISE À JOUR: En fait, si je le laisse courir un peu plus longtemps (avec toutes ces options) environ la moitié du temps, il tombe soudainement à 150 m après 4 ou 5 secondes (l'autre moitié, il ne baisse pas). Ce qui rend cela vraiment étrange, c'est que mon programme n'a pas de stochastique (et comme je l'ai dit, il est simple), il n'y a donc aucune raison pour qu'il se comporte différemment sur différentes exécutions

Cela pourrait-il avoir quelque chose à voir avec la machine virtuelle Java que j'utilise?

Java version "1.6.0_27"
OpenJDK Runtime Environment (IcedTea6 1.12.3) (6b27-1.12.3-0ubuntu1~10.04)
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode)

Selon Java -h, la JVM par défaut est -server. J'ai essayé d'ajouter -cacao et maintenant (avec toutes les autres options) c'est seulement 59m. Donc je suppose que cela résout mon problème. expliquer pourquoi cela était nécessaire? De plus, y a-t-il des inconvénients que je devrais connaître?

Une dernière mise à jour: cacao est vraiment très lent par rapport au serveur. C'est une terrible option

25
dspyz

La commande supérieure reflète la quantité totale de mémoire utilisée par l'application Java. Cela inclut entre autres:

  • Une surcharge de mémoire de base de la machine virtuelle Java elle-même
  • l'espace de tas (délimité par -Xmx)
  • L'espace de génération permanent (-XX: MaxPermSize - pas standard dans toutes les JVM)
  • espace de pile de threads (-Xss par pile) qui peut augmenter considérablement en fonction du nombre de threads
  • Espace utilisé par les allocations natives (à l'aide de la classe ByteBufer ou JNI)
16
Eyal Schneider
Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss]

ici la mémoire de tas max comme -Xmx, la mémoire de tas min comme -Xms, la mémoire de pile comme -Xss et -XX maxPermSize

L'exemple suivant illustre cette situation. J'ai lancé mon Tomcat avec les paramètres de démarrage suivants:

-Xmx168m -Xms168m -XX:PermSize=32m -XX:MaxPermSize=32m -Xss1m
7
amicos

Avec -Xmx vous configurez la taille du tas. Pour configurer la taille de la pile, utilisez -Xss paramètre. La somme de ces deux paramètres devrait être approximativement ce que vous voulez:

-Xmx150m -Xss50m

par exemple.

En outre, il existe également -XX:MaxPermSize paramètre qui contrôle. Ce paramètre pour -client a une valeur par défaut de 32 Mo et pour -server 64 Mo. Selon votre configuration, calculez-le également. L'espace PermGen est:

La génération permanente est utilisée pour refléter le VM lui-même, comme les objets de classe et les objets de méthode.

Donc, fondamentalement, il stocke les données internes de la JVM, comme les définitions de classes et les chaînes internes.

À la fin, je dois dire qu'il y a une partie que vous ne pouvez pas contrôler, c'est la mémoire utilisée par le processus natif Java. Java est un programme, juste comme les autres, il utilise donc également la mémoire. Si vous regardez l'utilisation de la mémoire dans le Gestionnaire des tâches, vous verrez cette mémoire ainsi que la consommation de mémoire de votre programme.

5
partlov

Il est important de noter que la "mémoire totale utilisée" (RSS dans le pays Linux) inclut le tas JDK (+ autres zones JDK) ainsi que toute "mémoire native" allouée.

Par exemple, ces personnes ont constaté que l'allocation d'un trop grand nombre de jaxbcontexts (qui ont associé de la mémoire native) entre les GC pourrait lui faire utiliser beaucoup de RAM supplémentaire. Un autre courant est apparemment ZipInflater si vous n'appelez pas à proximité (ou GZipStream, etc.)

http://sleeplessinslc.blogspot.com/2014/08/jvm-native-memory-leak.html

Sa solution de contournement/correction finale consistait soit à GC "plus souvent" (en utilisant GC1 garbage collector, soit en spécifiant un plus petit [ironiquement] paramètre -Xmx) ou en mettant en cache les objets JaxBContext (car ils n'ont pas de méthode close, vous ne pouvez donc pas contrôler la fuite).

Notez également que parfois vous pouvez trouver des coupables de mémoire en examinant simplement jstack: http://javaeesupportpatterns.blogspot.com/2011/09/jaxbcontext-performance-problem-case.html

Il est également parfois possible de "manquer" la fermeture par exemple de GZipStreams accidentellement http://kohsuke.org/2011/11/03/quiz-time-memory-leak-in-Java

3
rogerdpack

Avez-vous essayé d'utiliser JVisualVM?

http://docs.Oracle.com/javase/6/docs/technotes/tools/share/jvisualvm.html

J'ai souvent trouvé que cela m'aide à retrouver ces informations. Il vous montrera la quantité de chaque type de mémoire utilisée, vous permettant même de percer et de découvrir quoi.

1
danpaq