java.lang.OutOfMemoryError: espace de tas Java

96

J'obtiens l'erreur suivante lors de l'exécution d'un programme multi-thread

java.lang.OutOfMemoryError: Java heap space

L'erreur ci-dessus s'est produite dans l'un des threads.

  1. À ma connaissance, l'espace de tas est occupé par des variables d'instance uniquement. Si cela est correct, alors pourquoi cette erreur s'est produite après une exécution correcte pendant un certain temps, car de l'espace pour les variables d'instance est alloué au moment de la création de l'objet.

  2. Existe-t-il un moyen d'augmenter l'espace du tas?

  3. Quelles modifications dois-je apporter à mon programme pour qu'il prenne moins d'espace sur le tas?

Yatendra Goel
la source

Réponses:

104

Si vous souhaitez augmenter votre espace de tas, vous pouvez utiliser java -Xms<initial heap size> -Xmx<maximum heap size>sur la ligne de commande. Par défaut, les valeurs sont basées sur la version JRE et la configuration du système. Vous pouvez en savoir plus sur les options de VM sur le site Web Java .

Cependant, je recommanderais de profiler votre application pour savoir pourquoi la taille de votre tas est consommée. NetBeans a un très bon profileur inclus avec lui. Je crois qu'il utilise le jvisualvmsous le capot. Avec un profileur, vous pouvez essayer de trouver où de nombreux objets sont créés, quand les objets sont récupérés, et plus encore.

Thomas Owens
la source
1
J'utilise Netbeans mais je ne sais pas comment utiliser le profileur. J'aimerais en savoir plus sur le profileur afin de pouvoir l'utiliser pour trouver des fuites mémoire dans mon application.
Yatendra Goel
J'ai ajouté un lien vers une page du site NetBeans ( profiler.netbeans.org ) qui contient une très bonne documentation sur le profil, des bases les plus avancées à l'utilisation.
Thomas Owens
Les valeurs par défaut changent avec les versions java, ce serait bien d'inclure cette information dans votre réponse.
Dariusz
Je viens de résoudre un problème similaire et j'ai d'abord essayé: java -jar division.jar -Xmx512m -Xms512m - cela me donne la même erreur mais quand je le fais comme ça: java -Xmx512m -Xms512m -jar division.jar - tout va bien. Ainsi, l'ordre des paramètres est également important.
hipokito
@hipokito Les arguments après le fichier jar sont transmis à la méthode main () du fichier jar en tant que args []
Asu
29

1.- Oui, mais cela fait à peu près référence à toute la mémoire utilisée par votre programme.

2.- Oui, voir les options Java VM

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size

C'est à dire

java -Xmx2g attribuez 2 gigaoctets de RAM au maximum à votre application

Mais vous devriez voir si vous n'avez pas de fuite de mémoire en premier.

3.- Cela dépend du programme. Essayez de repérer les fuites de mémoire. Cette question serait trop difficile à répondre. Dernièrement, vous pouvez profiler en utilisant JConsole pour essayer de savoir où va votre mémoire

OscarRyz
la source
while which (true);)
Gal Bracha
8

Vous pouvez consulter ce site pour en savoir plus sur la mémoire dans la JVM: http://developer.streamezzo.com/content/learn/articles/optimization-heap-memory-usage

J'ai trouvé utile d'utiliser visualgc pour observer comment les différentes parties du modèle de mémoire se remplissent, pour déterminer ce qu'il faut changer.

Il est difficile de déterminer quelle partie de la mémoire a été remplie, donc visualgc, car vous voudrez peut-être simplement changer la partie qui a un problème, plutôt que de simplement dire,

Bien! Je vais donner 1G de RAM à la JVM.

Essayez d'être plus précis sur ce que vous faites, à long terme, vous trouverez probablement le programme meilleur pour cela.

Pour déterminer où se trouve la fuite de mémoire, vous pouvez utiliser des tests unitaires pour cela, en testant quelle était la mémoire avant le test et après, et s'il y a un changement trop important, vous pouvez l'examiner, mais vous devez effectuez la vérification pendant que votre test est toujours en cours.

James Black
la source
6

Pour augmenter la taille du tas, vous pouvez utiliser l'argument -Xmx lors du démarrage de Java; par exemple

-Xmx256M
Adamski
la source
6

Vous pouvez obtenir la taille de la mémoire de votre tas via le programme ci-dessous.

public class GetHeapSize {
    public static void main(String[] args) {
        long heapsize = Runtime.getRuntime().totalMemory();
        System.out.println("heapsize is :: " + heapsize);
    }
} 

puis en conséquence, vous pouvez également augmenter la taille du tas en utilisant: java -Xmx2g http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

user2663609
la source
6
  1. À ma connaissance, l'espace de tas est occupé par des variables d'instance uniquement. Si cela est correct, alors pourquoi cette erreur s'est produite après une exécution correcte pendant un certain temps, car de l'espace pour les variables d'instance est alloué au moment de la création de l'objet.

Cela signifie que vous créez plus d'objets dans votre application sur une période de temps en continu. Les nouveaux objets seront stockés dans la mémoire du tas et c'est la raison de la croissance de la mémoire du tas.

Heap ne contient pas seulement des variables d'instance. Il stockera tous les types de données non primitifs (objets). La durée de vie de ces objets peut être courte (bloc de méthode) ou longue (jusqu'à ce que l'objet soit référencé dans votre application)

  1. Existe-t-il un moyen d'augmenter l'espace du tas?

Oui. Jetez un œil à cet article sur l' oracle pour plus de détails.

Il existe deux paramètres pour définir la taille du tas:

-Xms:, qui définit la taille initiale et minimale du tas

-Xmx:, qui définit la taille maximale du tas

  1. Quelles modifications dois-je apporter à mon programme pour qu'il prenne moins d'espace sur le tas?

Cela dépend de votre application.

  1. Définissez la mémoire maximale du tas selon les besoins de votre application

  2. Ne provoquez pas de fuites de mémoire dans votre application

  3. Si vous trouvez des fuites de mémoire dans votre application, trouvez la cause principale à l'aide d'outils de profilage comme MAT , Visual VM , jconsole, etc. Une fois que vous avez trouvé la cause principale, corrigez les fuites.

Notes importantes de l' article d' Oracle

Cause: Le message détaillé Espace de tas Java indique que l'objet n'a pas pu être alloué dans le tas Java. Cette erreur n'implique pas nécessairement une fuite de mémoire.

Raisons possibles:

  1. Mauvaise configuration (pas d'allocation de mémoire suffisante)
  2. L'application contient involontairement des références à des objets et cela empêche les objets d'être récupérés
  3. Applications qui utilisent excessivement les finaliseurs. Si une classe a une méthode finalize, alors les objets de ce type n'ont pas leur espace récupéré au moment du garbage collection. Si le thread du finaliseur ne peut pas suivre le rythme avec la file d'attente de finalisation, le tas Java pourrait se remplir et ce type d'exception OutOfMemoryError serait levé .

Sur une note différente, utilisez de meilleurs algorithmes de récupération de place ( CMS ou G1GC )

Jetez un œil à cette question pour comprendre G1GC

Ravindra babu
la source
5
  1. Dans la plupart des cas, le code n'est pas optimisé. Libérez les objets dont vous pensez qu'ils ne seront plus nécessaires. Évitez à chaque fois de créer des objets dans votre boucle. Essayez d'utiliser des caches. Je ne sais pas comment va votre application. Mais dans la programmation, une règle de la vie normale s'applique également

    Mieux vaut prévenir que guérir. "Ne créez pas d'objets inutiles"

DKSRathore
la source
3
  1. Les variables locales sont situées sur la pile. L'espace de tas est occupé par des objets.

  2. Vous pouvez utiliser l' -Xmxoption.

  3. Fondamentalement, l'espace du tas est utilisé chaque fois que vous allouez un nouvel objet avec newet libéré un certain temps après que l'objet n'est plus référencé. Assurez-vous donc de ne pas conserver les références aux objets dont vous n'avez plus besoin.

sepp2k
la source
1

Non, je pense que vous pensez à l'espace de pile. L'espace de tas est occupé par des objets. Le moyen de l'augmenter est -Xmx256m, en remplaçant le 256 par le montant dont vous avez besoin sur la ligne de commande.

Yishai
la source
1

Pour éviter cette exception, si vous utilisez JUnit et Spring, essayez d'ajouter ceci dans chaque classe de test:

@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
Aliuk
la source
0

Dans netbeans, allez dans la barre d'outils 'Exécuter', -> 'Définir la configuration du projet' -> 'Personnaliser' -> 'exécuter' de sa fenêtre contextuelle -> 'Option VM' -> remplir '-Xms2048m -Xmx2048m '. Cela pourrait résoudre un problème de taille de tas.

Xiaogang
la source