Domanda cosa, oltre agli oggetti Class, è memorizzato in Perm Gen Space (sole 1.6 VM)?


Sto visualizzando 'java.lang.OutOfMemoryError: PermGen space' durante l'esecuzione di ~ 300 test JUnit e utilizzando il contesto Spring. Avere un momento difficile capire cosa sta mangiando PermGen dal:

  • allo stato stazionario l'app consuma circa 90m di spazio permgen
  • Ho provato -XX: MaxPermSize = 256m per i test delle unità - ancora in via di esaurimento
  • Con -XX:+TraceClassLoading e -XX:+TraceClassUnloading abilitato, non vedo ulteriori eventi di "caricamento" durante l'esecuzione degli ultimi 20-30 test prima del OutOfMemoryError.

Sembra che quest'ultimo suggerisca che qualcosa oltre agli oggetti Class stia riempiendo PermGen, no? Se sì, cosa potrebbe essere? Ad esempio, ci sono circostanze in cui classe casi sono memorizzati in PermGen?

Ecco le mie informazioni sulla VM:

$ java -version
java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)

relazionato

FWIW, la radice del mio problema che ha accelerato questo post si è rivelata alquanto banale: ho ipotizzato che il plugin Maven Surefire ereditasse le impostazioni VM da MAVEN_OPTS (o istanza VM che esegue mvn) quando forca una VM - non è così (Boo). Si deve specificare quelli che usano esplicitamente argLine nella configurazione del plugin. HTH.


15
2018-06-14 17:31


origine


risposte:


A volte abuso di String.Intern () può causare errori di spazio PermGen poiché le istanze String interne sono archiviate in PermGen.

Questo potrebbe essere ciò che stai vedendo - prova a eliminare le chiamate String.intern () non necessarie per vedere se questo risolve il problema. In generale, non consiglierei di usare String.intern () a meno che tu non sia sicuro che entrambe le seguenti condizioni siano vere:

  • Sei sicuro che verrà aggiunto solo un numero limitato di stringhe
  • In realtà, è necessario che tali stringhe condividano la stessa identità oggetto (ad esempio se molte istanze delle stesse stringhe consumano quantità inaccettabili di memoria o è necessario fare affidamento su == per il confronto delle stringhe per motivi di prestazioni complessi)

4
2018-06-14 17:37



Stringhe internate vengono anche memorizzate in permgen, sebbene siano improbabili centinaia di megabyte di stringhe sseems. Ricorda che ogni Spring Bean per il quale stai usando i proxy sta generando nuove classi al volo in fase di esecuzione per implementare le interfacce che stai trasmettendo. (Oppure i tuoi corsi se stai usando i proxy CGLIB, ecc.) Quindi, se stai creando un ApplicationContext Spring "fresco" per ogni JUnit, in effetti stai sfornando 300 copie di tutti i tuoi proxy, ecc.

Ricorda anche che le istanze di Class sono univoche per classloader, non attraverso l'intero spazio permgen, quindi possono esserci duplicati a seconda di come sono impostate le tue esecuzioni (se implicano la distribuzione in un contenitore o qualcosa del genere, anche se ciò sembra improbabile anche in un JUnit :)).


2
2018-06-14 17:40



Ho notato che stai utilizzando una JVM a 64 bit. Questi sono noti per utilizzare il doppio della memoria effettiva della macchina perché richiede uno spazio doppio di memoria per allocazione.

Se si dispone di test JUnit che effettivamente caricano un contesto primaverile (non così Unità dopo tutto), questi istanzeranno TUTTI i fagioli nel proprio appContext. Molto probabilmente richiederà più di 128mb (256 MB su una scatola da 64 bit) di memoria.

Nella mia esperienza, non è assurdo assegnare un mezzo concerto o più a una grande suite di test su una macchina a 64 bit. Prova a portarlo su 512mb o anche 1gb.

Queste sono le opzioni che gestisco una delle suite di test del mio progetto più grande con ...

-Xms256m
-Xmx512m
-XX:MaxPermSize=512m

1
2018-06-14 17:44