Quand et comment un chargeur de classe Java est-il marqué pour le nettoyage de la mémoire?

Nous créons plusieurs chargeurs de classes enfants à charger dans plusieurs sous-applications dans une application Java “container”, prototypant le déploiement à chaud. Lorsque le chemin de classe d’un chargeur de classe particulier a changé (les jars ont été ajoutés, supprimés, mis à jour), l’ancien classloader est jeté (non référencé) et un nouveau classloader est créé pour le nouveau classpath des jars.

Après avoir mis à jour le classpath, ce qui a déclenché le déploiement à chaud, nous avons effectué un vidage du tas. Le vidage du tas (à l’aide de Memory Analyzer) indique que les anciens chargeurs de classes n’étaient pas nettoyés. Certaines classes du chargeur de classes parent mettaient en cache les anciens chargeurs de classes. Les éléments suivants ont été appelés pour effacer ces caches:

java.lang.ResourceBundle.clearCache(classLoader); org.apache.commons.logging.LogFactory.release(classLoader); java.beans.Introspector.flushCaches(); 

Même après avoir effacé les caches ci-dessus, l’ancien chargeur de classes n’était toujours pas nettoyé. Les références restantes au classloader étaient les suivantes:

  • les classes chargées par le classloader
  • java.lang.Package créé par le chargeur de classes lui-même
  • java.lang.ProtectionDomain créé par le chargeur de classes lui-même

Toutes les références ci-dessus sont des références circulaires dans le chargeur de classes, ce qui devrait déclencher une récupération de place. Je ne suis pas sûr pourquoi. Est-ce que quelqu’un sait pourquoi les anciens chargeurs de classe ne sont toujours pas collectés, même avec les références circulaires?