java.lang.OutOfMemoryError: limite de surcharge du GC dépassée

Je reçois cette erreur dans un programme qui crée plusieurs objects HashMap (des centaines de milliers) avec quelques (15-20) entrées de texte chacune. Ces chaînes doivent toutes être collectées (sans se décomposer en plus petites quantités) avant d’être soumises à une firebase database.

Selon Sun, l’erreur se produit “si trop de temps est passé dans la récupération de place: si plus de 98% du temps total est consacré à la récupération de place et que moins de 2% du tas est récupéré, une erreur OutOfMemory sera levée. “.

Apparemment, on pourrait utiliser la ligne de commande pour transmettre des arguments à la JVM pour

  • Augmenter la taille du tas, via “-Xmx1024m” (ou plus), ou
  • Désactiver la vérification des erreurs, via “-XX: -UseGCOverheadLimit”.

La première approche fonctionne bien, la seconde se termine dans une autre erreur java.lang.OutOfMemoryError, cette fois sur le tas.

Donc, question: y a-t-il une alternative programmatique à cela, pour le cas d’utilisation particulier (par exemple, plusieurs petits objects HashMap)? Si j’utilise la méthode HashMap clear (), par exemple, le problème disparaît, mais les données stockées dans HashMap le sont aussi! 🙂

Le problème est également abordé dans une rubrique connexe de StackOverflow.

    Vous êtes essentiellement à court de mémoire pour exécuter le processus en douceur. Des options qui viennent à l’esprit:

    1. Spécifiez plus de mémoire comme vous l’avez mentionné, essayez d’abord quelque chose comme -Xmx512m
    2. Travailler avec de plus petits lots d’objects HashMap pour les traiter HashMap si possible
    3. Si vous avez beaucoup de chaînes en double, utilisez Ssortingng.intern() dessus avant de les HashMap dans HashMap
    4. Utilisez le constructeur HashMap(int initialCapacity, float loadFactor) pour ajuster votre cas

    Ce qui suit a fonctionné pour moi. Ajoutez simplement l’extrait suivant:

     dexOptions { javaMaxHeapSize "4g" } 

    Pour votre build.gradle :

     android { comstackSdkVersion 23 buildToolsVersion '23.0.1' defaultConfig { applicationId "yourpackage" minSdkVersion 14 targetSdkVersion 23 versionCode 1 versionName "1.0" multiDexEnabled true } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } packagingOptions { } dexOptions { javaMaxHeapSize "4g" } } 

    @takrl: Le paramètre par défaut pour cette option est:

     java -XX:+UseConcMarkSweepGC 

    ce qui signifie que cette option n’est pas active par défaut. Donc, quand vous dites que vous avez utilisé l’option ” +XX:UseConcMarkSweepGC “, je suppose que vous utilisiez cette syntaxe:

     java -XX:+UseConcMarkSweepGC 

    ce qui signifie que vous activiez explicitement cette option. Pour la syntaxe et les parameters par défaut corrects de Java HotSpot VM Options @ ce document

    Pour mémoire, nous avons eu le même problème aujourd’hui. Nous avons résolu ce problème en utilisant cette option:

     -XX:-UseConcMarkSweepGC 

    Apparemment, cela modifiait la stratégie utilisée pour la collecte des ordures, ce qui faisait disparaître le problème.

    Ummm … tu devras soit:

    1. Repensez complètement votre algorithme et vos structures de données, de sorte qu’il ne nécessite pas tous ces petits HashMaps.

    2. Créez une façade qui vous permet de mettre en page ces cartes HashMaps de la mémoire selon vos besoins. Un simple cache LRU peut être simplement le ticket.

    3. Jusqu’à la mémoire disponible pour la JVM. Si nécessaire, même en achetant plus de mémoire vive, la solution la plus rapide et la moins chère, si vous avez la gestion de la machine qui héberge cette bête. Cela étant dit, je ne suis généralement pas fan des solutions «jeter plus de matériel informatique», surtout si une solution algorithmique alternative peut être imaginée dans un délai raisonnable. Si vous continuez à lancer plus de matériel à chacun de ces problèmes, vous rencontrerez bientôt la loi des rendements décroissants.

    Qu’est-ce que vous essayez réellement de faire de toute façon? Je pense qu’il y a une meilleure approche de votre problème réel.

    Utilisez une autre implémentation de HashMap ( Trove ). Java HashMap standard a une surcharge de mémoire> 12x. On peut lire les détails ici .

    Ne stockez pas toute la structure en mémoire en attendant de terminer.

    Écrire des résultats intermédiaires dans une table temporaire de la firebase database plutôt que hashmaps – fonctionnellement, une table de firebase database équivaut à un hashmap, c’est-à-dire que la table n’est pas liée à la mémoire. les hashmaps.

    Si cela est fait correctement, votre algorithme ne devrait même pas remarquer le changement – cela signifie correctement utiliser une classe pour représenter la table, même en lui donnant une méthode put (key, value) et une méthode get (key) comme un hashmap.

    Lorsque la table intermédiaire est terminée, générez les instructions SQL requirejses à partir de celle-ci et non de la mémoire.

    Le collecteur parallèle lancera une OutOfMemoryError si trop de temps est passé dans la récupération de place. En particulier, si plus de 98% du temps total est consacré à la récupération de place et que moins de 2% du OutOfMemoryError est récupéré, OutOfMemoryError sera lancé. Cette fonctionnalité est conçue pour empêcher les applications de s’exécuter pendant une période prolongée sans faire peu ou pas de progrès car le segment de mémoire est trop petit. Si nécessaire, cette fonctionnalité peut être désactivée en ajoutant l’option -XX:-UseGCOverheadLimit à la ligne de commande.

    Si vous créez des centaines de milliers de cartes de hachage, vous utilisez probablement beaucoup plus que ce dont vous avez réellement besoin; Sauf si vous travaillez avec des fichiers ou des graphiques volumineux, le stockage de données simples ne doit pas dépasser la limite de mémoire Java.

    Vous devriez essayer de repenser votre algorithme. Dans ce cas, j’offrirais plus d’aide à ce sujet, mais je ne peux donner aucune information tant que vous ne fournirez pas plus d’informations sur le contexte du problème.

    Si vous avez java8 et que vous pouvez utiliser G1 Garbage Collector , exécutez votre application avec:

      -XX:+UseG1GC -XX:+UseSsortingngDeduplication 

    Cela indique au G1 de trouver des chaînes similaires et d’en garder une seule en mémoire, et les autres ne sont qu’un pointeur sur cette chaîne en mémoire.

    Ceci est utile lorsque vous avez beaucoup de chaînes répétées. Cette solution peut ou non fonctionner et dépend de chaque application.

    Plus d’infos sur:
    https://blog.codecensortingc.de/en/2014/08/ssortingng-deduplication-new-feature-java-8-update-20-2/ http://java-performance.info/java-ssortingng-deduplication/

    Corrigez les memory leaks dans votre application à l’aide d’outils de profil tels que eclipse MAT ou VisualVM

    Avec JDK 1.7.x ou les versions ultérieures, utilisez G1GC , qui consacre 10% à la récupération de place, contrairement à 2% dans les autres algorithmes GC.

    Mis à part la mise en mémoire de tas avec -Xms1g -Xmx2g , essayez `

     -XX:+UseG1GC -XX:G1HeapRegionSize=n, -XX:MaxGCPauseMillis=m, -XX:ParallelGCThreads=n, -XX:ConcGCThreads=n` 

    Jetez un oeil à l’article d’ Oracle pour affiner ces parameters.

    Une question liée à G1GC en SE:

    Récupération de la mémoire Java 7 (JDK 7) et documentation sur G1

    Ramasse-miettes Java G1 en production

    Stratégie agressive de ramasse-miettes

    En cas d’erreur:

    “Erreur interne du compilateur: java.lang.OutOfMemoryError: dépassement de la limite de capacité du CPG à java.lang.AbstractSsortingngBuilder”

    Augmentez l’espace de -Xmx2g. Java à 2 Go, soit -Xmx2g.

    Vous devez augmenter la taille de la mémoire dans Jdeveloper allez dans setDomainEnv.cmd.

     set WLS_HOME=%WL_HOME%\server set XMS_SUN_64BIT=256 set XMS_SUN_32BIT=256 set XMX_SUN_64BIT=3072 set XMX_SUN_32BIT=3072 set XMS_JROCKIT_64BIT=256 set XMS_JROCKIT_32BIT=256 set XMX_JROCKIT_64BIT=1024 set XMX_JROCKIT_32BIT=1024 if "%JAVA_VENDOR%"=="Sun" ( set WLS_MEM_ARGS_64BIT=-Xms256m -Xmx512m set WLS_MEM_ARGS_32BIT=-Xms256m -Xmx512m ) else ( set WLS_MEM_ARGS_64BIT=-Xms512m -Xmx512m set WLS_MEM_ARGS_32BIT=-Xms512m -Xmx512m ) and set MEM_PERM_SIZE_64BIT=-XX:PermSize=256m set MEM_PERM_SIZE_32BIT=-XX:PermSize=256m if "%JAVA_USE_64BIT%"=="true" ( set MEM_PERM_SIZE=%MEM_PERM_SIZE_64BIT% ) else ( set MEM_PERM_SIZE=%MEM_PERM_SIZE_32BIT% ) set MEM_MAX_PERM_SIZE_64BIT=-XX:MaxPermSize=1024m set MEM_MAX_PERM_SIZE_32BIT=-XX:MaxPermSize=1024m 

    Pour cette utilisation ci-dessous le code dans votre fichier d’application gradation sous la fermeture Android.

    dexOptions {javaMaxHeapSize “4g”}

    Pour mon cas, augmenter la mémoire en utilisant l’option -Xmx était la solution.

    J’ai eu un fichier de 10g lu en Java et chaque fois j’ai eu la même erreur. Cela s’est produit lorsque la valeur de la colonne RES dans la commande top atteint la valeur définie dans l’option -Xmx. Ensuite, en augmentant la mémoire en utilisant l’option -Xmx , tout s’est bien passé.

    Il y avait aussi un autre point. Lorsque j’ai défini JAVA_OPTS ou CATALINA_OPTS dans mon compte d’utilisateur et augmenté la quantité de mémoire à nouveau, j’ai reçu la même erreur. Ensuite, j’ai imprimé la valeur de ces variables d’environnement dans mon code, ce qui m’a donné des valeurs différentes de celles que j’ai définies. La raison en était que Tomcat était la racine de ce processus et comme je n’étais pas un subalterne, j’ai demandé à l’administrateur d’augmenter la mémoire de catalina.sh dans Tomcat.

    Cela m’a aidé à me débarrasser de cette erreur. Cette option désactive -XX: + DisableExplicitGC