Java.lang.OutOfMemoryError: dépassement de la limite supérieure de la CG
j'obtiens cette erreur dans un programme qui crée plusieurs (centaines de milliers) objets HashMap avec quelques (15-20) entrées de texte chacune. Ces chaînes doivent toutes être collectées (sans se fractionner en plus petites quantités) avant d'être soumises à une base de données.
selon Sun, l'erreur se produit " si trop de temps est passé dans la collecte des ordures: si plus de 98% du temps total est passé dans la collecte des ordures et moins de 2% du tas est récupéré, un OutOfMemoryError sera jeté.".
Apparemment, on pourrait utiliser la ligne de commande pour passer des arguments à la JVM pour
- augmentation de la taille du tas, via "- Xmx1024m "(ou plus), ou
- Disabling the error check totally, via "- XX: - UseGCOverheadLimit".
la première approche fonctionne bien, la seconde se termine dans un autre java.lang.OutOfMemoryError, cette fois pour le tas.
alors, question: y a-t-il une alternative programmatique à cela, pour le cas d'utilisation particulier (c'est-à-dire plusieurs petits objets HashMap)? Si j'utilise la méthode HashMap clear (), par exemple, le problème disparaît, tout comme les données stockées dans HashMap! :- )
la question est également abordée dans un sujet connexe dans StackOverflow.
16 réponses
vous êtes essentiellement à court de mémoire pour exécuter le processus en douceur. Options qui viennent à l'esprit:
- spécifiez plus de mémoire comme vous l'avez mentionné, essayez quelque chose comme
-Xmx512m
premier - travailler avec des lots plus petits d'objets
HashMap
à traiter immédiatement si possible - si vous avez beaucoup de chaînes en double, utilisez
String.intern()
avant de les mettre dans leHashMap
- utilisez le
HashMap(int initialCapacity, float loadFactor)
le constructeur à accorder pour votre cas
ce qui suit a fonctionné pour moi. Il suffit d'ajouter l'extrait suivant:
dexOptions {
javaMaxHeapSize "4g"
}
à votre build.gradle
:
android {
compileSdkVersion 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 tu dis que tu as 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 correcte et les paramètres par défaut de Java HotSpot VM Options
@ ceci
document
pour info, on a eu le même problème aujourd'hui. Nous l'avons corrigé en utilisant cette option:
-XX:-UseConcMarkSweepGC
apparemment, cela a modifié la stratégie utilisée pour le ramassage des ordures, ce qui a fait disparaître le problème.
Ummm... vous aurez besoin de:
-
" complètement repenser votre algorithme et les structures de données, de sorte qu'il n'a pas besoin de tous ces petits Hachmaps.
-
créer une façade qui vous permet de page ces HashMaps Dans et hors de la mémoire comme nécessaire. Un simple LRU-cache pourrait être juste le billet.
-
la mémoire de la JVM. Si nécessaire, même acheter plus de RAM pourrait être 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 dit, Je ne suis généralement pas fan des solutions" plus de matériel", surtout si une solution algorithmique alternative peut être élaborée dans un délai raisonnable. Si vous continuez à jeter plus de matériel à chacun de ces problèmes vous bientôt dans la loi des rendements décroissants.
de Quoi êtes-vous en fait en essayant de le faire de toute façon? Je pense qu'il y a une meilleure façon d'aborder votre vrai problème.
ne conservez pas toute la structure en mémoire en attendant la fin.
écrire des résultats intermédiaires à une table temporaire dans la base de données au lieu de hashmaps - fonctionnellement, une table de base de données est l'équivalent d'un hashmap, c'est-à-dire que les deux supportent l'accès aux données par clavier, mais la table n'est pas liée à la mémoire, donc utilisez une table indexée ici plutôt que les hashmaps.
si fait correctement, votre algorithme ne devrait même pas remarquer le changement - correctement ici signifie utiliser une classe pour représenter la table, même en lui donnant une méthode put(clé, valeur) et get(clé) comme une hashmap.
lorsque la table intermédiaire est complète, générer la(les) Instruction (s) sql requise (s) à partir de celle-ci plutôt que de la mémoire.
le collecteur parallèle lancera un OutOfMemoryError
si trop de temps est consacré à la collecte des ordures. En particulier, si plus de 98% du temps total est consacré à la collecte des ordures et si moins de 2% du tas est récupéré, OutOfMemoryError
sera jeté. Cette fonctionnalité est conçue pour empêcher les applications de fonctionner pendant une période prolongée tout en faisant peu ou pas de progrès parce que le tas 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 hash, vous utilisez probablement beaucoup plus que ce dont vous avez réellement besoin; à moins que vous ne travailliez avec de grands fichiers ou des graphiques, le stockage de données simples ne devrait 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 n'en aurez pas plus sur le contexte du problème.
si vous avez java8 , et que vous pouvez utiliser le collecteur D'ordures G1 , alors exécutez votre application avec:
-XX:+UseG1GC -XX:+UseStringDeduplication
indique au G1 de trouver des chaînes similaires et de ne garder qu'une seule D'entre elles en mémoire, et les autres ne sont qu'un pointeur vers cette chaîne en mémoire.
c'est utile quand vous avez beaucoup de chaînes répétées. Cette solution peut ou non fonctionner et dépend de chaque application.
plus d'informations sur:
https://blog.codecentric.de/en/2014/08/string-deduplication-new-feature-java-8-update-20-2 /
http://java-performance.info/java-string-deduplication /
réparer les fuites de mémoire dans votre application à l'aide d'outils de profil comme eclipse MAT ou VisualVM
avec JDK 1.7.x
ou versions suivantes, Utiliser G1GC
, qui dépense 10% sur la collecte des ordures contrairement à 2% dans les autres algorithmes de GC.
mis à part la mise de mémoire tas avec -Xms1g -Xmx2g
, try '
-XX:+UseG1GC
-XX:G1HeapRegionSize=n,
-XX:MaxGCPauseMillis=m,
-XX:ParallelGCThreads=n,
-XX:ConcGCThreads=n`
regarder oracle article pour affiner ces paramètres.
Quelques question par rapport à l'G1GC en SOI:
Java 7 (JDK 7) collecte des ordures et documentation sur G1
En cas d'erreur:
"erreur Interne du compilateur: java.lang.OutOfMemoryError: limite de charge de GC dépassée à java.lang.AbstractStringBuilder "
augmenter l'espace java heap à 2 Go i.e., -Xmx2g.
vous devez augmenter la taille de la mémoire dans Jdeveloper aller à 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 code ci-dessous dans votre fichier app gradle sous android closure.
dexOptions { javaMaxHeapSize " 4g" }
pour mon cas l'augmentation de la mémoire en utilisant -Xmx
option était la solution.
j'ai eu un fichier 10g lu en java et à chaque fois j'ai eu la même erreur. Cela s'est produit lorsque la valeur dans la colonne RES
de la commande top
a atteint la valeur définie dans l'option-Xmx. Puis en augmentant la mémoire en utilisant l'option -Xmx
tout s'est bien passé.
il y avait aussi un autre point. Quand je mets JAVA_OPTS
ou CATALINA_OPTS
dans mon compte d'utilisateur et augmenté la quantité de mémoire à nouveau j'ai eu la même erreur. Ensuite, j'ai imprimé la valeur de ces variables d'environnement dans mon code qui m'ont donné des valeurs différentes de ce que j'ai défini. La raison en était que Tomcat était la racine de ce processus et puis comme je n'étais pas un sous-doer, j'ai demandé à l'administrateur d'augmenter la mémoire dans catalina.sh
dans Tomcat.
Cela m'a aidé à me débarrasser de cette erreur.Cette option désactive - XX: + Disablexplicitgc