Je reçois cette erreur dans un programme qui crée plusieurs objets (des centaines de milliers) HashMap avec quelques entrées de texte (15-20) chacune. Ces chaînes doivent toutes être collectées (sans être fragmentées) avant d'être soumises à une base de données.
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 passé dans la récupération de place et que moins de 2% du segment de mémoire est récupéré, une erreur OutOfMemoryError est générée. ".
Apparemment, on pourrait utiliser la ligne de commande pour transmettre des arguments à la machine virtuelle Java pour:
La première approche fonctionne bien, la seconde se termine dans un autre fichier Java.lang.OutOfMemoryError, cette fois à propos du tas.
Donc, question: existe-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, mais les données stockées dans HashMap! :-)
Le problème est également abordé dans un sujet associé dans StackOverflow.
Vous manquez de mémoire pour exécuter le processus en douceur. Les options qui me viennent à l’esprit:
-Xmx512m
en premierHashMap
à traiter simultanément si possibleString.intern()
avant de les placer dans le HashMap
HashMap(int initialCapacity, float loadFactor)
pour régler votre cas.Ce qui suit a fonctionné pour moi. Ajoutez simplement 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 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 avez explicitement activé cette option. Pour la syntaxe correcte et les paramètres par défaut de Java HotSpot VM Options
@ this document
Pour mémoire, nous avons 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 devrez soit:
Repensez complètement votre algorithme et vos structures de données, de sorte qu'il n'ait pas besoin de tous ces petits HashMaps.
Créez une façade qui vous permet de mettre en mémoire ces HashMaps en entrée et en sortie, selon vos besoins. Un simple cache LRU pourrait bien être le ticket.
Jusqu'à la mémoire disponible pour la machine virtuelle Java. 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 partisan des solutions "jetons plus de matériel", surtout si une solution algorithmique alternative peut être imaginée dans un délai raisonnable. Si vous continuez à utiliser plus de matériel pour résoudre chacun de ces problèmes, vous rencontrez rapidement la loi des rendements décroissants.
Qu'est-ce que vous essayez réellement de faire de toute façon? Je soupçonne qu'il existe une meilleure approche de votre problème actuel.
Ne stockez pas la totalité de la structure en mémoire en attendant la fin.
Écrivez les résultats intermédiaires dans une table temporaire de la base de données au lieu de hashmaps - fonctionnellement, une table de base de données équivaut à une table de hachage, c’est-à-dire que les deux prennent en charge l’accès avec clé aux données, mais que la table n’est pas liée à la mémoire. Utilisez donc une table indexée ici. les hashmaps.
Si cela est fait correctement, votre algorithme ne devrait même pas remarquer le changement - correctement, cela signifie utiliser une classe pour représenter la table, même en lui donnant une méthode put (clé, valeur) et une méthode get (clé), comme un hashmap.
Une fois la table intermédiaire terminée, générez la ou les instructions SQL requises à la place de la mémoire.
Le collecteur parallèle lancera un 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 segment 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 tout en faisant peu ou pas de progrès car 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 avez Java8 et que vous pouvez utiliser le collecteur de déchets G1 , puis lancez votre application avec:
-XX:+UseG1GC -XX:+UseStringDeduplication
Cela indique au G1 de rechercher des chaînes similaires et de n'en conserver qu'une seule en mémoire, les autres n'étant 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.codecentric.de/en/2014/08/string-deduplication-new-feature-Java-8-update-20-2/http://Java-performance.info/Java-string-deduplication/
Si vous créez des centaines de milliers de cartes de hachage, vous en 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 davantage d'aide à ce sujet, mais je ne peux donner aucune information tant que vous n'en donnez pas davantage sur le contexte du problème.
Corrigez les fuites de mémoire dans votre application à l'aide d'outils de profil tels qu'Eclipse MAT ou VisualVM
Avec JDK 1.7.x
ou les versions ultérieures, utilisez G1GC
, qui dépense 10% en garbage collection, contrairement à 2% dans d'autres algorithmes de GC.
En plus de définir la mémoire de tas avec -Xms1g -Xmx2g
, essayez
-XX:+UseG1GC
-XX:G1HeapRegionSize=n,
-XX:MaxGCPauseMillis=m,
-XX:ParallelGCThreads=n,
-XX:ConcGCThreads=n`
Consultez l'article Oracle pour affiner ces paramètres.
Quelques questions liées à G1GC dans SE:
récupération de place Java 7 (JDK 7) et documentation sur G1
En cas d'erreur:
"Erreur interne du compilateur: Java.lang.OutOfMemoryError: dépassement de la limite de temps système GC dans Java.lang.AbstractStringBuilder"
augmenter l'espace de tas Java à 2 Go, c'est-à-dire -Xmx2g.
Vous devez augmenter la taille de la mémoire dans Jdeveloper, allez à 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 cela, utilisez ci-dessous le code dans votre fichier de graduation d’application sous Android fermeture.
dexOptions {javaMaxHeapSize "4g"}
Pour mon cas, augmenter la mémoire avec l'option -Xmx
était la solution.
J'ai eu un fichier 10g lu dans Java et à chaque fois j'ai la même erreur. Cela s'est produit lorsque la valeur de la colonne RES
de la commande top
a atteint la valeur définie dans l'option -Xmx. Ensuite, en augmentant la mémoire avec 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 que j'ai augmenté la quantité de mémoire, la même erreur s'est produite. 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 exécutant, j'ai demandé à l'administrateur d'augmenter la mémoire dans catalina.sh
dans Tomcat.
Cela m'a aidé à supprimer cette erreur. Cette option désactive -XX: + DisableExplicitGC