Je te remercie pour ces explications clair et schématisées
Envoyé par
tchize_
En effet, le seul moyen de garbage collecter une classe, c'est que son classloader soit garbage collecté. Et celui-ci ne peut l'etre que si il n'est plus référencé nulle part et si aucune des classes qui l'a chargée n'est référencée ailleurs (donc ni par des références directes classe<?>, ni par des instances, ni par des références indirectes aux instances, etc, regles habituelles de gc).
Je sais bien, c'est justement ce que je recherche à faire
Tu pense donc qu'aprés avoir utilisé la fonction "retireruneClasse(class1)", la classe "class 2" sera tjrs référencée par la classe de test "Main" ?
Mon but était le suivant :
1 - classloader1 : class1 + class2 (classes chargées)
2 - retirer "class1" :
classloader1 : class1 + class2
création du ClassLoader classloader2
classloader2 : class2
3 - Déférencer classloader1
4 - Utilisation du GC
Je détail un peu plus mon code :
Le chargeur/déchargeur de classe :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| import java.util.HashSet;
import java.util.Set;
public class ChargeurDeClassesImpl implements ChargeurDeClassesI{
private Set <String> classesCharges = new HashSet<String>();
private ClassLoader classLoader;
public ChargeurDeClassesImpl(){
/*
* Ce code créé un chargeur de classes, ce qui nécessite un test de sécurité.
* Même si ce code possède des droits suffisants, la création du chargeur de classes
* devrait être effectuée dans un block doPrivileged au cas ou il serait appelé par
* du code ne possédant pas les droits requis.
*/
classLoader = new MyClassLoader();
}
/**
* Charge à la demande un fichier ".class" et instancie la classe Class<?> correspondante.
* @param nom Nom de la classe à charger.
* @return Classe chargée.
*/
public Class<?> chargerUneClasse(String nom) throws Exception{
if(nom == null)return null;
//true (utilisation de la méthode resolve du classloader) : permet de charger les classes utilisés par la classe "nom" à charger.
//classLoader = Thread.currentThread().getContextClassLoader() ;
//classLoader = java.lang.ClassLoader.getSystemClassLoader() ;
Class<?> classACharger = Class.forName(nom, true, classLoader);
//Class<?> classACharger = classLoader.loadClass(nom);
if(classACharger==null) return null;
classACharger.newInstance();
classesCharges.add(nom);
return classACharger;
}
/**
* Décharge la classe passée en paramétre.
* Le déchargement effectif des classes est laissé à l'initiative du ramasse-miettes.
* Le ramasse-miettes libère l'espace mémoire utilisé par le chargeur de classes auquel certaines classes
* auront été retirées et retire implicitement les instances de la classe Class<?> qui ne sont plus référencées.
*
* @param nom Nom de la classe à décharger.
* @return Le chargeur de classe.
*/
public ChargeurDeClassesI retirerUneClasse(String nom) throws Exception{
// à compléter
if(nom == null)return null;
classesCharges.remove(nom);
ChargeurDeClassesI nouveauChargeurDeClass = new ChargeurDeClassesImpl();
for (String nomClass : classesCharges) {
// Class.forName(nom, true,java.lang.ClassLoader.getSystemClassLoader() ).
nouveauChargeurDeClass.chargerUneClasse(nomClass);
}
//classLoader = null;
return nouveauChargeurDeClass;
//return this;
} |
Le test (classe Main):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.lang.management.*;
import javax.management.*;
public class Main{
public static void main(String[] args)throws Exception{
ClassLoadingMXBean classLoading = ManagementFactory.getClassLoadingMXBean();
classLoading.setVerbose(true); // pour le vérifier à la console
//System.out.println("<classLoading.getLoadedClassCount(),classLoading.getTotalLoadedClassCount(),getUnloadedClassCount()>");
//System.out.println("<" + classLoading.getLoadedClassCount() + "," + classLoading.getTotalLoadedClassCount()+ "," + classLoading.getUnloadedClassCount() + ">");
ChargeurDeClassesI cc = new ChargeurDeClassesImpl();
cc.chargerUneClasse("question1.A");
cc.chargerUneClasse("question1.C"); // 2 classes chargées : A et C
ChargeurDeClassesI cc1 = cc.retirerUneClasse("question1.C");
cc=null; System.gc();
// 2 classes "déchargées" par le ramasse-miettes : A et C, de cc
System.out.println("UnloadedClassCount() : " + classLoading.getUnloadedClassCount());
}
} |
Le loader custo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| import java.io.*;
import java.util.*;
public class MyClassLoader extends ClassLoader{
private Map<String,Class<?>> classes;
public MyClassLoader(){
super(MyClassLoader.class.getClassLoader());
classes = new HashMap<String,Class<?>>();
}
protected synchronized Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException{
Class <?> classe = classes.get(name); // ou bien sans classes, Class classe = findLoadedClass(name);
if (classe == null) {
byte[] classBytes = loadClassBytes(name);
if (classBytes == null){
return findSystemClass(name);
}
classe = defineClass(name, classBytes, 0, classBytes.length);
if (classe == null)
throw new ClassNotFoundException(name);
classes.put(name, classe);
}
if (resolve) resolveClass(classe);
return classe;
}
private byte[] loadClassBytes(String name){
String cname = name.replace('.', '/') + ".class";
FileInputStream in = null;
try{
in = new FileInputStream(cname);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int ch;
while ((ch = in.read()) != -1){
byte b = (byte)(ch);
buffer.write(b);
}
in.close();
return buffer.toByteArray();
}catch (IOException e){
if (in != null){
try {in.close(); } catch (IOException e2) { }
}
return null;
}
}
} |
Ce classloader te semble-t-il approprié ?
Partager