2014-10-19 17 views
15

Ho questo codice per generare classe in modo dinamico e caricarloJava8 metaspace & mucchio utilizzo

import javassist.CannotCompileException; 
import javassist.ClassPool; 

public class PermGenLeak { 
    private static final String PACKAGE_NAME = "com.jigarjoshi.permgenleak."; 

    public static void main(String[] args) throws CannotCompileException, InterruptedException { 
     for (int i = 0; i < Integer.MAX_VALUE; i++) { 
      ClassPool pool = ClassPool.getDefault(); 
      pool.makeClass(PACKAGE_NAME + i).toClass(); 
      Thread.sleep(3); 
     } 

    } 
} 

ho lanciato questa classe contro Java 7 (jdk1.7.0_60) e come previsto è riempito PermGenSpace e heap è rimasto inutilizzato Java 7 memory usage immagine mostra PermGen straordinari utilizzo e alla JVM fine è stato terminato

Ora lo stesso codice ha funzionato contro Java 8 (jdk1.8.0_40-bis) e come previsto ha mantenuto espansione di memoria nativa (Metaspace) ma sorprendentemente per 1g di Metaspace ha consumato 3g di Heap in OldGen (almos t 3x di Metaspace mantenuta nel tempo)

Java8 memory usage immagine mostra l'utilizzo Metaspace straordinari e campione utilizzo della memoria di sistema

this email from Jon Masamitsu e this JEP ticket dice

internati String e Classe statistiche e alcuni dati misc ha stato spostato su Heap

cosa fa esattamente questo aumento di heap mentre carica più classi in Metaspace?

risposta

10

Eseguire jmap -histo PID per vedere quali oggetti consumano lo spazio di heap.
Quando ho eseguito il tuo esempio ho visto il mucchio pieno di Javassist oggetti ausiliari:

num  #instances   #bytes class name 
---------------------------------------------- 
    1:  592309  312739152 [Ljavassist.bytecode.ConstInfo; 
    2:  6515673  208501536 java.util.HashMap$Node 
    3:  2964403  169188824 [C 
    4:  1777622  102165184 [Ljava.lang.Object; 
    5:  4146200  99508800 javassist.bytecode.Utf8Info 
    6:  3553889  85293336 java.util.ArrayList 
    7:  2964371  71144904 java.lang.String 
    8:  593075  56944008 java.lang.Class 
    9:  592332  47388032 [Ljava.util.HashMap$Node; 
    10:  592309  37907776 javassist.bytecode.ClassFile 
    11:  592308  37907712 javassist.CtNewClass 
    12:  1185118  28555808 [B 
    13:  592342  28432416 java.util.HashMap 
    14:  1184624  28430976 javassist.bytecode.ClassInfo 
    15:  592309  28430832 [[Ljavassist.bytecode.ConstInfo; 
    16:  592322  23692880 javassist.bytecode.MethodInfo 
    17:  592315  23692600 javassist.bytecode.CodeAttribute 
    18:  592434  18957888 java.util.Hashtable$Entry 
    19:  592309  18953888 javassist.bytecode.ConstPool 
    20:  592308  18953856 java.lang.ref.WeakReference 
    21:  592318  14215632 javassist.bytecode.MethodrefInfo 
    22:  592318  14215632 javassist.bytecode.NameAndTypeInfo 
    23:  592315  14215560 javassist.bytecode.ExceptionTable 
    24:  592309  14215416 javassist.bytecode.LongVector 
    25:  592309  14215416 javassist.bytecode.SourceFileAttribute 
    26:  592507  9487584 [I 
    27:    8  6292528 [Ljava.util.Hashtable$Entry; 
    28:   212   18656 java.lang.reflect.Method 
    29:   407   13024 java.util.concurrent.ConcurrentHashMap$Node 
    30:   124   8928 java.lang.reflect.Field 
+0

Grazie Andrei, avrei dovuto solo eseguire questo, penso che non ho raggiunto a questa scala in Java 7 esempio è per questo che non l'ho visto in Java 7 –

3

cosa fa esattamente questo aumento di heap mentre carica più classi in Metaspace?

La mia ipotesi è che questa è spazzatura "ordinaria" che viene creata dal tuo esempio. Suppongo che:

  • Il codice javaassist crea oggetti mucchio regolari. Sono per lo più "grandi" e questo fa sì che vengano allocati direttamente nell'heap di OldGen. O qualcos'altro lo causa.

    (AGGIORNAMENTO - guardando @ di apangin risposta, ora il sospetto che hanno iniziato nel mucchio YoungGen ed erano di ruolo ...)

  • Quando classLoader.defineClass è chiamato sotto il cofano, che crea oggetti in metaspace dall'array di byte contenente il file di classe.

  • L'utilizzo di OldGen rimane ... perché non è ancora stato attivato un GC completo.

Se ottimizzato il tuo esempio in modo che le classi erano raggiungibili, e poi costretti a GC pieno, mi aspetterei (speranza) per vedere l'utilizzo OldHeap a goccia, a indicare che si tratta di spazzatura "ordinario", piuttosto che una perdita di stoccaggio.

+0

Grazie Stefano, E 'del tutto ha senso ora, penso che non ho raggiungo a questa scala di ripartizione in Java 7 esempio, che è perché non l'ho visto in Java 7 –