Question

J'écris un côté client Balançoire application (concepteur de polices graphiques) sur Java5.Récemment, je suis tombé sur java.lang.OutOfMemoryError: Java heap space erreur car je ne suis pas conservateur sur l'utilisation de la mémoire.L'utilisateur peut ouvrir un nombre illimité de fichiers et le programme conserve les objets ouverts en mémoire.Après une recherche rapide, j'ai trouvé Ergonomie dans la machine virtuelle Java 5.0 et d'autres disent que sur la machine Windows, la taille de tas maximale par défaut de la JVM est la suivante 64MB.

Face à cette situation, comment dois-je gérer cette contrainte ?

Je pourrais augmenter le taille maximale du tas en utilisant ligne de commande option à Java, mais cela nécessiterait de déterminer la RAM disponible et d'écrire un programme ou un script de lancement.En outre, augmentant à certains fini max ne le fait pas finalement débarrassez-vous du problème.

Je pourrais réécrire une partie de mon code pour conserver fréquemment les objets dans le système de fichiers (l'utilisation de la base de données est la même chose) afin de libérer de la mémoire.Cela pourrait fonctionner, mais cela représente probablement aussi beaucoup de travail.

Si vous pouviez m'indiquer les détails des idées ci-dessus ou des alternatives comme mémoire virtuelle automatique, étendant dynamiquement la taille du tas, ce sera génial.

Était-ce utile?

La solution

En fin de compte, vous disposez toujours d'un nombre maximum de tas à utiliser, quelle que soit la plate-forme sur laquelle vous utilisez.Sous Windows 32 bits, c'est autour 2GB (pas spécifiquement le tas mais la quantité totale de mémoire par processus).Il se trouve que Java choisit de réduire la valeur par défaut (sans doute pour que le programmeur ne puisse pas créer de programmes avec une allocation de mémoire incontrôlable sans rencontrer ce problème et devoir examiner exactement ce qu'ils font).

Ceci étant donné, vous pouvez adopter plusieurs approches pour déterminer la quantité de mémoire dont vous avez besoin ou pour réduire la quantité de mémoire que vous utilisez.Une erreur courante avec les langages de garbage collection tels que Java ou C# est de conserver les références aux objets que vous plus maintenant utilisez ou allouez de nombreux objets alors que vous pourriez réutilisation eux à la place.Tant que les objets ont une référence à eux, ils continueront à utiliser l'espace de mémoire car le ramasse-miettes ne les supprimera pas.

Dans ce cas, vous pouvez utiliser un profileur de mémoire Java pour déterminer quelles méthodes de votre programme allouent un grand nombre d'objets, puis déterminer s'il existe un moyen de vous assurer qu'ils ne sont plus référencés ou de ne pas les allouer en premier lieu.Une option que j'ai utilisée dans le passé est "JMP". http://www.khelekore.org/jmp/.

Si vous déterminez que vous allouez ces objets pour une raison et que vous devez conserver des références (selon ce que vous faites, cela peut être le cas), il vous suffira d'augmenter la taille maximale du tas lorsque vous démarrez le programme.Cependant, une fois que vous avez effectué le profilage de la mémoire et compris comment vos objets sont alloués, vous devriez avoir une meilleure idée de la quantité de mémoire dont vous avez besoin.

En général, si vous ne pouvez pas garantir que votre programme fonctionnera dans une quantité limitée de mémoire (peut-être en fonction de la taille de l'entrée), vous rencontrerez toujours ce problème.Ce n'est qu'après avoir épuisé tout cela que vous devrez vous pencher sur la mise en cache des objets sur le disque, etc.À ce stade, vous devriez avoir une très bonne raison de dire "J'ai besoin de X Go de mémoire" pour quelque chose et vous ne pouvez pas contourner ce problème en améliorant vos algorithmes ou vos modèles d'allocation de mémoire.En général, cela ne sera le cas que pour les algorithmes fonctionnant sur de grands ensembles de données (comme une base de données ou un programme d'analyse scientifique), et des techniques telles que la mise en cache et les E/S mappées en mémoire deviennent alors utiles.

Autres conseils

Exécutez Java avec l'option de ligne de commande -Xmx, qui fixe le maximum taille du tas.

Voir ici pour plus de détails.

Vous pourriez préciser par projetez la quantité d'espace de stockage souhaitée par votre projet

Ce qui suit est pour Éclipse Hélios/Junon/Kepler:

Cliquez avec le bouton droit de la souris sur

 Run As - Run Configuration - Arguments - Vm Arguments, 

puis ajoute ceci

-Xmx2048m

Augmenter la taille du tas n'est pas une "correction", c'est un "plâtre", 100% temporaire.Il va planter à nouveau ailleurs.Pour éviter ces problèmes, écrivez du code hautes performances.

  1. Utilisez des variables locales dans la mesure du possible.
  2. Assurez-vous de sélectionner le bon objet (EX :Sélection entre String, StringBuffer et StringBuilder)
  3. Utilisez un bon système de code pour votre programme (EX :Utilisation de variables statiques VS variables non statiques)
  4. D'autres éléments qui pourraient fonctionner sur votre code.
  5. Essayez de vous déplacer avec multi THREADING

Grosse mise en garde ---- dans mon bureau, nous avons constaté que (sur certaines machines Windows) nous ne pouvions pas allouer plus de 512 m pour le tas Java.Cela s'est avéré être dû au produit antivirus Kaspersky installé sur certaines de ces machines.Après avoir désinstallé ce produit audiovisuel, nous avons constaté que nous pouvions allouer au moins 1,6 Go, c'est-à-dire -Xmx1600m (m est obligatoire sinon cela entraînera une autre erreur "Tas initial trop petit") fonctionne.

Je ne sais pas si cela se produit avec d'autres produits audiovisuels, mais cela se produit probablement parce que le programme audiovisuel réserve un petit bloc de mémoire dans chaque espace d'adressage, empêchant ainsi une seule allocation très importante.

Les arguments de la VM ont fonctionné pour moi dans Eclipse.Si vous utilisez Eclipse version 3.4, procédez comme suit

aller à Run --> Run Configurations --> puis sélectionnez le projet sous maven build --> puis sélectionnez l'onglet "JRE" --> puis entrez -Xmx1024m.

Alternativement, vous pourriez faire Run --> Run Configurations --> select the "JRE" tab --> puis entrez -Xmx1024m

Cela devrait augmenter la mémoire pour toutes les versions/projets.La taille de la mémoire ci-dessus est de 1 Go.Vous pouvez optimiser comme vous le souhaitez.

Oui, avec -Xmx vous pouvez configurer plus de mémoire pour votre JVM.Pour être sûr de ne pas fuir ou gaspiller de la mémoire.Faites un vidage de tas et utilisez l'analyseur de mémoire Eclipse pour analyser votre consommation de mémoire.

Je voudrais ajouter des recommandations d'Oracle dépannage article.

Exception dans le fil thread_name : java.lang.OutOfMemoryError :Java heap space

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

Causes possibles:

  1. Problème de configuration simple, où la taille de segment spécifiée est insuffisante pour l'application.

  2. L'application contient involontairement des références à des objets, ce qui empêche les objets d'être récupérés.

  3. Utilisation excessive des finaliseurs.

Une autre source potentielle de cette erreur provient des applications qui utilisent excessivement les finaliseurs.Si une classe a une méthode finalize, alors les objets de ce type ne voient pas leur espace récupéré au moment du garbage collection

Après collecte des ordures, les objets sont mis en file d'attente pour finalisation, qui se produit plus tard. finaliseurs sont exécutés par un thread démon qui dessert la file d'attente de finalisation.Si la finaliseur le thread ne peut pas suivre la file d'attente de finalisation, alors le tas Java pourrait se remplir et ce type de Erreur de mémoire insuffisante une exception serait levée.

Un scénario pouvant provoquer cette situation est celui où une application crée fils de discussion hautement prioritaires qui provoquent le finalisation la file d'attente augmente à un rythme plus rapide que le rythme auquel le thread du finaliseur gère cette file d'attente.

Suivez les étapes ci-dessous :

  1. Ouvrir catalina.sh de tomcat/bin.

  2. Remplacez JAVA_OPTS par

    JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1536m 
    -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m 
    -XX:MaxPermSize=256m -XX:+DisableExplicitGC"
    
  3. Redémarrez votre Tomcat

Un moyen facile de résoudre OutOfMemoryError en Java consiste à augmenter la taille maximale du tas en utilisant les options JVM -Xmx512M, cela résoudra immédiatement votre OutOfMemoryError.C'est ma solution préférée lorsque j'obtiens OutOfMemoryError dans Eclipse, Maven ou ANT lors de la création d'un projet, car en fonction de la taille du projet, vous pouvez facilement manquer de mémoire.

Voici un exemple d'augmentation de la taille maximale du tas de la JVM. Il est également préférable de conserver le rapport -Xmx à -Xms soit 1:1, soit 1:1,5 si vous définissez la taille du tas dans votre application Java.

export JVM_ARGS="-Xms1024m -Xmx1024m"

Lien de référence

Par défaut, pour le développement, la JVM utilise une petite taille et une petite configuration pour d'autres fonctionnalités liées aux performances.Mais pour la production, vous pouvez régler par ex.(De plus, une configuration spécifique au serveur d'applications peut exister) -> (S'il n'y a toujours pas assez de mémoire pour satisfaire la demande et que le tas a déjà atteint la taille maximale, une erreur OutOfMemoryError se produira)

-Xms<size>        set initial Java heap size
-Xmx<size>        set maximum Java heap size
-Xss<size>        set java thread stack size

-XX:ParallelGCThreads=8
-XX:+CMSClassUnloadingEnabled
-XX:InitiatingHeapOccupancyPercent=70
-XX:+UnlockDiagnosticVMOptions
-XX:+UseConcMarkSweepGC
-Xms512m
-Xmx8192m
-XX:MaxPermSize=256m (in java 8 optional)

Par exemple:Sur la plate-forme Linux pour les paramètres préférables en mode production.

Après avoir téléchargé et configuré le serveur de cette façon http://www.ehowstuff.com/how-to-install-and-setup-apache-tomcat-8-on-centos-7-1-rhel-7/

1.créez le fichier setenv.sh sur le dossier /opt/tomcat/bin/

   touch /opt/tomcat/bin/setenv.sh

2.Ouvrez et écrivez ces paramètres pour définir le mode préférable.

nano  /opt/tomcat/bin/setenv.sh 

export CATALINA_OPTS="$CATALINA_OPTS -XX:ParallelGCThreads=8"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+CMSClassUnloadingEnabled"
export CATALINA_OPTS="$CATALINA_OPTS -XX:InitiatingHeapOccupancyPercent=70"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UnlockDiagnosticVMOptions"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseConcMarkSweepGC"
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx8192m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxMetaspaceSize=256M"

3.service tomcat restart

Notez que la JVM utilise plus de mémoire que le tas.Par exemple, les méthodes Java, les piles de threads et les poignées natives sont allouées dans la mémoire distincte du tas, ainsi que les structures de données internes JVM.

J'ai rencontré le même problème avec la taille du tas Java.

J'ai deux solutions si vous utilisez Java 5(1.5).

  1. installez simplement jdk1.6 et accédez aux préférences d'Eclipse et définissez le chemin jre de jav1 1.6 tel que vous l'avez installé.

  2. Vérifiez votre argument VM et laissez-le tel qu'il est.Ajoutez simplement une ligne ci-dessous de tous les arguments présents dans les arguments VM comme -xms512m -xmx512m -xx: maxpermSize = ... m (192m).

Je pense que cela va fonctionner...

J'ai lu ailleurs que vous pouvez essayer - catch java.lang.OutOfMemoryError et sur le bloc catch, vous pouvez libérer toutes les ressources dont vous savez qu'elles pourraient utiliser beaucoup de mémoire, fermer les connexions, etc., puis faire un System.gc() puis réessayez ce que vous alliez faire.

Une autre façon est la suivante, cependant, je ne sais pas si cela fonctionnerait, mais je teste actuellement si cela fonctionnera sur mon application.

L'idée est d'effectuer un garbage collection en appelant System.gc(), connu pour augmenter la mémoire libre.Vous pouvez continuer à vérifier cela après l’exécution d’un code engloutissant la mémoire.

//Mimimum acceptable free memory you think your app needs
long minRunningMemory = (1024*1024);

Runtime runtime = Runtime.getRuntime();

if(runtime.freeMemory()<minRunningMemory)
 System.gc();

Si vous devez surveiller votre utilisation de la mémoire au moment de l'exécution, le java.lang.management offres forfaitaires MBeans qui peut être utilisé pour surveiller les pools de mémoire de votre VM (par exemple, l'espace Eden, la génération titulaire, etc.), ainsi que le comportement du garbage collection.

L'espace de tas libre signalé par ces MBeans varie considérablement en fonction du comportement du GC, en particulier si votre application génère de nombreux objets qui sont ensuite édités par GC.Une approche possible consiste à surveiller l'espace libre du tas après chaque GC complet, que vous pourrez peut-être utiliser pour prendre une décision sur la libération de mémoire par des objets persistants.

En fin de compte, le mieux est de limiter autant que possible la rétention de mémoire tout en gardant les performances acceptables.Comme l'a noté un commentaire précédent, la mémoire est toujours limitée, mais votre application doit avoir une stratégie pour gérer l'épuisement de la mémoire.

Notez que si vous en avez besoin dans une situation de déploiement, envisagez d'utiliser Java WebStart (avec une version "ondisk", pas celle réseau - possible dans Java 6u10 et versions ultérieures) car il vous permet de spécifier les différents arguments de la JVM dans un message croisé. manière de la plate-forme.

Sinon, vous aurez besoin d'un lanceur spécifique au système d'exploitation qui définit les arguments dont vous avez besoin.

Si ce problème se produit dans Wildfly 8 et JDK1.8, nous devons alors spécifier les paramètres MaxMetaSpace au lieu des paramètres PermGen.

Par exemple, nous devons ajouter la configuration ci-dessous dans le fichier setenv.sh de wildfly.JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=256M"

Pour plus d'informations, veuillez consulter Problème de tas de mouches sauvages

En ce qui concerne NetBeans, vous pouvez définir la taille maximale du tas pour résoudre le problème.

Allez dans 'Exécuter', puis --> 'Définir la configuration du projet' --> 'Personnaliser' --> 'exécuter' de sa fenêtre contextuelle --> 'Option VM' --> remplissez '-Xms2048m -Xmx2048m' .

Si vous continuez à allouer et à conserver des références à un objet, vous remplirez toute la quantité de mémoire dont vous disposez.

Une option consiste à fermer et ouvrir un fichier transparent lorsqu'il change d'onglet (vous ne gardez qu'un pointeur sur le fichier, et lorsque l'utilisateur change d'onglet, vous fermez et nettoyez tous les objets...cela ralentira le changement de fichier...mais...), et peut-être ne garder que 3 ou 4 fichiers en mémoire.

Une autre chose que vous devez faire est, lorsque l'utilisateur ouvre un fichier, de le charger et d'intercepter toute erreur OutOfMemoryError, puis (comme il n'est pas possible d'ouvrir le fichier) de fermer ce fichier, de nettoyer ses objets et d'avertir l'utilisateur qu'il doit fermer les objets inutilisés. des dossiers.

Votre idée d'étendre dynamiquement la mémoire virtuelle ne résout pas le problème, car la machine est limitée en ressources, vous devez donc être prudent et gérer les problèmes de mémoire (ou du moins, être prudent avec eux).

Voici quelques indices que j'ai vus concernant les fuites de mémoire :

--> Gardez à l'esprit que si vous mettez quelque chose dans une collection et que vous l'oubliez ensuite, vous y avez toujours une forte référence, alors annulez la collection, nettoyez-la ou faites quelque chose avec...sinon, vous aurez du mal à trouver une fuite de mémoire.

--> Peut-être qu'utiliser des collections avec des références faibles (weakhashmap...) peut aider à résoudre les problèmes de mémoire, mais vous doit soyez prudent, car vous constaterez peut-être que l'objet que vous recherchez a été récupéré.

--> Une autre idée que j'ai trouvée est de développer une collection persistante stockée sur les objets de base de données les moins utilisés et chargés de manière transparente.Ce serait probablement la meilleure approche...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top