Est-il possible de forcer le ramasse-miettes en Java, même si c'est délicat à faire? Je connais System.gc();
et Runtime.gc();
mais ils suggèrent seulement de faire GC. Comment puis-je forcer le GC?
Est-il possible de forcer le ramasse-miettes en Java, même si c'est délicat à faire? Je connais System.gc();
et Runtime.gc();
mais ils suggèrent seulement de faire GC. Comment puis-je forcer le GC?
Réponses:
Votre meilleure option est d'appeler System.gc()
ce qui est simplement un indice pour le garbage collector que vous voulez qu'il fasse une collecte. Il n'y a aucun moyen de forcer et de collecter immédiatement, car le garbage collector n'est pas déterministe.
non-deterministic == trouble
GC.Collect()
ne recueille pas. En Java gc()
fait.
La bibliothèque jlibs a une bonne classe utilitaire pour la récupération de place . Vous pouvez forcer la collecte des ordures à l'aide d'une astuce astucieuse avec des objets WeakReference .
RuntimeUtil.gc () des jlibs:
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
PhantomReference
avec un ReferenceQueue
et ensuite vous seriez averti après la finalisation, mais toujours avant le nettoyage. Enfin, même si vous avez détecté avec succès que la mémoire de cet objet a été récupérée, cela signifierait encore très peu dans un GC générationnel comme HotSpot. Habituellement, cela coïncidait avec le nettoyage de la jeune génération.
System.gc(); System.gc();
, mais il serait certainement intéressant de savoir si cela a jamais fonctionné mieux que cela. En fait, il suffit d’imprimer le nombre de fois qu’il a appelé System.gc()
. La chance d'atteindre jamais 2 est assez mince.
La meilleure (sinon la seule) façon de forcer un GC serait d'écrire une JVM personnalisée. Je crois que les collecteurs de déchets sont enfichables, vous pouvez donc probablement choisir l'une des implémentations disponibles et la modifier.
Remarque: ce n'est PAS une réponse facile.
À l'aide de l' interface Java ™ Virtual Machine Tool (JVM TI) , la fonction
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
"Force la machine virtuelle à effectuer une récupération de place". La JVM TI fait partie de l' architecture de débogage de plate-forme JavaTM (JPDA) .
OUI il est presque possible de forcer vous devez appeler des méthodes dans le même ordre et en même temps celles-ci sont:
System.gc ();
System.runFinalization ();
même s'il n'y a qu'un seul objet à nettoyer, l'utilisation de ces deux méthodes en même temps force le garbage collector à utiliser la finalise()
méthode de l'objet inaccessible en libérant la mémoire affectée et en faisant ce que la finalize()
méthode indique.
TOUTEFOIS, c'est une pratique terrible d'utiliser le garbage collector car son utilisation pourrait introduire une surcharge du logiciel qui peut être pire que celle de la mémoire, le garbage collector a son propre thread qui n'est pas possible de contrôler plus en fonction de l'algorithme utilisé par le gc pourrait prendre plus de temps et est considéré comme très inefficace, vous devriez vérifier votre logiciel s'il est pire avec l'aide du gc car il est définitivement cassé, une bonne solution ne doit pas dépendre du gc.
REMARQUE: juste pour garder à l'esprit que cela ne fonctionnera que si dans la méthode de finalisation n'est pas une réaffectation de l'objet, si cela se produit, l'objet restera en vie et il aura une résurrection qui est techniquement possible.
gc()
n'est qu'un indice pour exécuter un garbage collection. runFinalizers()
exécute uniquement les finaliseurs sur les objets "dont on a constaté qu'ils étaient rejetés". Si le GC n'a pas réellement fonctionné, il n'y a peut-être pas de tels objets ...
Dans la documentation d' OutOfMemoryError, il déclare qu'il ne sera pas jeté à moins que la machine virtuelle n'ait pas réussi à récupérer de la mémoire après un garbage collection complet. Donc, si vous continuez d'allouer de la mémoire jusqu'à ce que vous obteniez l'erreur, vous aurez déjà forcé une récupération de place complète.
Vraisemblablement, la question que vous vouliez vraiment poser était "comment puis-je récupérer la mémoire que je pense que je devrais récupérer par la collecte des ordures?"
Pour demander manuellement GC (pas à partir de System.gc ()):
.gc est un candidat à l'élimination dans les versions futures - un ingénieur Sun a un jour déclaré que peut-être moins de vingt personnes dans le monde savent réellement comment utiliser .gc () - j'ai fait du travail la nuit dernière pendant quelques heures sur une centrale / critique structure de données utilisant des données générées par SecureRandom, quelque part juste après 40 000 objets, la VM ralentirait comme si elle était à court de pointeurs. De toute évidence, il étouffait les tables de pointeurs 16 bits et présentait un comportement classique de "machines défaillantes".
J'ai essayé -Xms et ainsi de suite, j'ai continué à tourner jusqu'à ce qu'il atteigne environ 57, xxx quelque chose. Ensuite, il exécuterait gc allant de disons 57.127 à 57.128 après un gc () - à peu près au rythme du code au camp Easy Money.
Votre conception nécessite une refonte fondamentale, probablement une approche de fenêtre coulissante.
Vous pouvez déclencher un GC à partir de la ligne de commande. Ceci est utile pour batch / crontab:
jdk1.7.0/bin/jcmd <pid> GC.run
Voir:
La spécification JVM ne dit rien de spécifique sur la récupération de place. Pour cette raison, les fournisseurs sont libres d'implémenter GC à leur manière.
Ce flou entraîne donc une incertitude dans le comportement de collecte des ordures. Vous devriez vérifier les détails de votre JVM pour connaître les approches / algorithmes de récupération de place. Il existe également des options pour personnaliser le comportement.
Si vous devez forcer la récupération de place, vous devriez peut-être réfléchir à la façon dont vous gérez les ressources. Créez-vous de gros objets qui persistent dans la mémoire? Créez-vous des objets volumineux (par exemple, des classes graphiques) qui ont une Disposable
interface et n'appelez-vous pas dispose()
lorsque vous en avez terminé? Déclarez-vous quelque chose au niveau de la classe dont vous n'avez besoin que dans une seule méthode?
Il serait préférable de décrire la raison pour laquelle vous avez besoin d'un ramasse-miettes. Si vous utilisez SWT, vous pouvez disposer de ressources telles que Image
et Font
pour libérer de la mémoire. Par exemple:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
Il existe également des outils pour déterminer les ressources non utilisées.
Si vous manquez de mémoire et que OutOfMemoryException
vous en obtenez un, vous pouvez essayer d'augmenter la quantité d'espace disponible sur java en démarrant votre programme avec java -Xms128m -Xmx512m
au lieu de simplement java
. Cela vous donnera une taille de tas initiale de 128 Mo et un maximum de 512 Mo, ce qui est bien plus que le 32 Mo / 128 Mo standard.
java -Xms512M -Xmx1024M
Une autre option consiste à ne pas créer de nouveaux objets.
Le regroupement d'objets est loin pour réduire le besoin de GC en Java.
Le regroupement d'objets ne va généralement pas être plus rapide que la création d'objets (en particulier pour les objets légers) mais il est plus rapide que Garbage Collection. Si vous avez créé 10 000 objets et que chaque objet faisait 16 octets. C'est 160 000 octets que GC doit récupérer. D'un autre côté, si vous n'avez pas besoin de tous les 10000 en même temps, vous pouvez créer un pool pour recycler / réutiliser les objets, ce qui élimine le besoin de construire de nouveaux objets et élimine le besoin d'anciens objets GC.
Quelque chose comme ça (non testé). Et si vous voulez qu'il soit sûr pour les threads, vous pouvez échanger la LinkedList contre une ConcurrentLinkedQueue.
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
Sur OracleJDK 10 avec G1 GC, un seul appel à System.gc()
provoquera le nettoyage de l'ancienne collection par GC. Je ne sais pas si GC fonctionne immédiatement. Cependant, GC ne nettoiera pas la Young Collection même si elle System.gc()
est appelée plusieurs fois dans une boucle. Pour que GC nettoie la Young Collection, vous devez allouer en boucle (par exemple new byte[1024]
) sans appeler System.gc()
. L'appel System.gc()
pour une raison quelconque empêche GC de nettoyer la collection Young.
Vraiment, je ne vous comprends pas. Mais pour être clair sur "Infinite Object Creation", je voulais dire qu'il y a un morceau de code sur mon grand système qui crée des objets qui se manipulent et qui vivent en mémoire, je n'ai pas pu obtenir ce morceau de code en fait, juste un geste !!
C'est correct, seulement un geste. Vous avez à peu près les réponses standard déjà données par plusieurs affiches. Prenons celui-ci un par un:
Exact, il n'y a pas de jvm réel - ce n'est qu'une spécification, un tas d'informatique décrivant un comportement souhaité ... J'ai récemment creusé l'initialisation des objets Java à partir du code natif. Pour obtenir ce que vous voulez, la seule façon est de faire ce que l'on appelle une annulation agressive. Les erreurs si mal faites sont si mauvaises que nous devons nous limiter à la portée initiale de la question:
La plupart des affiches ici supposeront que vous dites que vous travaillez sur une interface, si tel est le cas, nous devrions voir si vous recevez l'objet entier ou un élément à la fois.
Si vous n'avez plus besoin d'un objet, vous pouvez attribuer null à l'objet mais si vous vous trompez, une exception de pointeur null est générée. Je parie que vous pouvez obtenir un meilleur travail si vous utilisez NIO
Chaque fois que vous ou moi ou quelqu'un d'autre obtient: " S'il vous plaît, j'en ai horriblement besoin. " C'est un précurseur presque universel de la destruction presque totale de ce sur quoi vous essayez de travailler .... écrivez-nous un petit exemple de code, aseptisant de tout code réel utilisé et montrez-nous votre question.
Ne soyez pas frustré. Souvent, cela résout le problème: votre dba utilise un package acheté quelque part et la conception d'origine n'est pas modifiée pour les structures de données massives.
C'est très courant.
FYI
L'appel de méthode System.runFinalizersOnExit (true) garantit que les méthodes du finaliseur sont appelées avant l'arrêt de Java. Cependant, cette méthode est intrinsèquement dangereuse et a été déconseillée. Une alternative consiste à ajouter des «hooks d'arrêt» avec la méthode Runtime.addShutdownHook.
Masarrat Siddiqui
Il existe un moyen indirect de forcer le ramasse-miettes. Il vous suffit de remplir le tas d'objets temporaires jusqu'au moment où le garbage collector s'exécutera. J'ai fait une classe qui force le garbage collector de cette façon:
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
Usage:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
Je ne sais pas à quel point cette méthode est utile, car elle remplit constamment le tas, mais si vous avez une application critique qui DOIT forcer GC - quand cela peut être la manière portable Java de forcer GC.
Je voudrais ajouter quelque chose ici. Veuillez noter que Java ne fonctionne pas sur une machine virtuelle et non sur une machine réelle. La machine virtuelle a son propre moyen de communication avec la machine. Il peut varier d'un système à l'autre. Maintenant, lorsque nous appelons le GC, nous demandons à la machine virtuelle de Java d'appeler le garbage collector.
Étant donné que le garbage collector est avec une machine virtuelle, nous ne pouvons pas le forcer à effectuer un nettoyage sur place. Plutôt que nous mettons en file d'attente notre demande avec le garbage collector. Cela dépend de la machine virtuelle, après un temps particulier (cela peut changer d'un système à l'autre, généralement lorsque la mémoire de seuil allouée à la JVM est pleine), la machine réelle libérera de l'espace. :RÉ
Le code suivant est extrait de la méthode assertGC (...). Il essaie de forcer le ramasse-miettes non déterministe à collecter.
List<byte[]> alloc = new ArrayList<byte[]>();
int size = 100000;
for (int i = 0; i < 50; i++) {
if (ref.get() == null) {
// Test succeeded! Week referenced object has been cleared by gc.
return;
}
try {
System.gc();
} catch (OutOfMemoryError error) {
// OK
}
try {
System.runFinalization();
} catch (OutOfMemoryError error) {
// OK
}
// Approach the jvm maximal allocatable memory threshold
try {
// Allocates memory.
alloc.add(new byte[size]);
// The amount of allocated memory is increased for the next iteration.
size = (int)(((double)size) * 1.3);
} catch (OutOfMemoryError error) {
// The amount of allocated memory is decreased for the next iteration.
size = size / 2;
}
try {
if (i % 3 == 0) Thread.sleep(321);
} catch (InterruptedException t) {
// ignore
}
}
// Test failed!
// Free resources required for testing
alloc = null;
// Try to find out who holds the reference.
String str = null;
try {
str = findRefsFromRoot(ref.get(), rootsHint);
} catch (Exception e) {
throw new AssertionFailedErrorException(e);
} catch (OutOfMemoryError err) {
// OK
}
fail(text + ":\n" + str);
Source (j'ai ajouté quelques commentaires pour plus de clarté): Exemple NbTestCase
Vous pouvez essayer d'utiliser Runtime.getRuntime().gc()
ou d'utiliser une méthode utilitaire System.gc()
Remarque: Ces méthodes ne garantissent pas le GC. Et leur portée doit être limitée à la JVM plutôt que de la gérer par programme dans votre application.