2016-12-16 2 views
0

Je le code suivant qui génère (intentionnellement) un PermGen java.lang.OutOfMemoryError:Drapeaux pour PermGen ne fonctionne pas comme prévu: -XX: + CMSClassUnloadingEnabled et -XX: + CMSPermGenSweepingEnabled


public class Main { 

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, InterruptedException { 
     String name = "MyClass"; 
     DynamicClassLoader cl = new DynamicClassLoader(); 

     int i = 0; 
     while (true) { 
      //code for generating the binary for a class to be loaded. 
      ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); 
      cw.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, name + ++i, null, "java/lang/Object", null); 
      MethodVisitor con = cw.visitMethod(Opcodes.ACC_PUBLIC, "", "()V", null, null); 
      con.visitCode(); 
      con.visitVarInsn(Opcodes.ALOAD, 0); 
      con.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "", "()V", false); 
      con.visitInsn(Opcodes.RETURN); 
      con.visitMaxs(1, 1); 
      cw.visitEnd(); 
      //binary code for class successfully generated 

      Class clazz = cl.defineClass(name + i, cw.toByteArray()); 
      Object o = clazz.newInstance(); 
      System.out.println(o.getClass().getName()); 
     } 
    } 

    private static class DynamicClassLoader extends ClassLoader { 
     public Class defineClass(String name, byte[] b) { 
      return defineClass(name, b, 0, b.length); 
     } 
    } 
} 

J'exécuter ce code en Java 7 Comme prévu, il obtient java.lang.OutOfMemoryError: PermGen space erreur. Lorsque je tente de lancer ce programme avec les drapeaux mentionnés comme suit:

java -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled -jar target/permgen.jar 

, je reçois toujours la même erreur, à exactement au même point que quand je le lance sans drapeaux. Je m'attendais à ce que si je mets ces drapeaux, sinon un rafraîchissement total de PermGen se produirait, au moins une amélioration partielle serait vu. Mais ce n'est pas le cas.

Question: Ai-je mal compris la signification de ces drapeaux? Pouvez-vous détailler si c'est le cas, s'il vous plaît? Sinon, des suggestions?

N.B. Sortie de java -version est:

java version "1.7.0_95"

OpenJDK Runtime Environment (IcedTea 2.6.4) (7u95-2.6.4-3)

OpenJDK 64 bits serveur VM (build 24.95-b01, mode mixte)

+2

Pouvez-vous modifier votre cas de test afin que votre instance de 'DynamicClassLoader' ne soit pas conservée pendant toute la durée du test? AFAIK, tous les classloaders conservent une référence à toutes les classes qu'ils chargent. Sauf si votre classloader est GC'ed, vos classes ne peuvent pas être GC'ed. – omajid

+0

@omajid Merci. Tu frappes l'ongle. :) Veuillez le poster comme réponse afin de l'accepter. – artaxerxe

Répondre

1

Tous les chargeurs de classes conservent de fortes références à toutes les classes qu'ils chargent. Dans votre exemple, vous continuez à réutiliser l'instance unique de DynamicClassLoader. Ce classloader conserve à son tour des références solides à toutes les classes que vous chargez. Ainsi, le récupérateur de place ne voit jamais les objets non référencés qu'il peut collecter.

Si vous modifiez votre scénario de test pour utiliser des chargeurs de classe distincts, Garbage Collector devrait être capable d'identifier que vos classes ne sont pas utilisées et devrait récupérer la mémoire.