Domanda

forma breve: Il collettore CMS garbage sembra essere non riuscendo a raccogliere una quantità sempre crescente di spazzatura; alla fine, il nostro JVM si riempie, e l'applicazione non risponde. Forzare un GC tramite uno strumento esterno (JConsole o jmap -histo:live) si pulisce volta.

UPDATE: Il problema sembra essere correlato al plugin JTop per JConsole; se non corriamo JConsole, o eseguirlo senza il plugin JTop, il comportamento va via.

(Note tecniche:.. Siamo in esecuzione Sun JDK 1.6.0_07, a 32 bit, su una macchina Linux 2.6.9 Aggiornamento alla versione JDK non è davvero un'opzione, a meno che non ci sia un inevitabile, motivo principale Inoltre, il nostro sistema non è collegato a una macchina accessibile via Internet, in modo da screenshot di JConsole, ecc non sono un'opzione.)

Stiamo attualmente in esecuzione il nostro JVM con le seguenti bandiere:

-server -Xms3072m -Xmx3072m -XX:NewSize=512m -XX:MaxNewSize=512m 
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled 
-XX:CMSInitiatingOccupancyFraction=70 
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 
-XX:+DisableExplicitGC

Osservando il grafico di memoria in JConsole, c'è un GC completo che passa ogni ~ 15 minuti o giù di lì durante le prime ore di durata della vita della nostra applicazione; dopo ogni GC pieno, non c'è più e più memoria ancora in uso. Dopo alcune ore, il sistema colpisce uno stato stazionario dove c'è circa 2GB di memoria utilizzata nel CMS vecchia generazione.

che suona come una perdita di memoria classica, tranne che se usiamo qualsiasi strumento che le forze di GC completo (premendo il pulsante "raccogliere i rifiuti" in JConsole, o in esecuzione jmap -histo:live, ecc), la vecchia generazione scende improvvisamente a ~ 500MB usati , e la nostra applicazione diventa reattivo ancora per le ore successive (durante i quali lo stesso modello continua -. dopo ogni GC pieno, sempre di più della vecchia generazione è piena)

Una cosa da notare: in JConsole, l'ha riportato conteggio ConcurrentMarkSweep GC rimarrà a 0 finché non si forza un GC con jconsole / jmap / etc

.

Utilizzando jmap -histo e jmap -histo:live in sequenza, sono in grado di determinare che gli oggetti apparentemente non riscossi sono costituiti da:

  • diversi milioni di HashMaps e array di HashMap$Entry (in un rapporto 1: 1)
  • diversi milioni Vectors e array oggetto (rapporto 1: 1, e circa lo stesso del numero di HashMaps)
  • diversi milioni HashSet, Hashtable e com.sun.jmx.remote.util.OrderClassLoaders, così come array di Hashtable$Entry (circa lo stesso numero di ciascuna; circa la metà di quelli dei HashMaps e Vettori)

Ci sono alcuni estratti del GC di uscita al di sotto; la mia interpretazione di essi sembra essere che il CMS GC è sempre interrotta senza failover al GC stop-il-mondo. Sto interpretando male questa uscita in qualche modo? C'è qualcosa che potrebbe causare questo?

Nel corso della fase di esecuzione normale, i blocchi di uscita CMS GC guardarsi intorno in questo modo:

36301.827: [GC [1 CMS-initial-mark: 1856321K(2621330K)] 1879456K(3093312K), 1.7634200 secs] [Times: user=0.17 sys=0.00, real=0.18 secs]
36303.638: [CMS-concurrent-mark-start]
36314.903: [CMS-concurrent-mark: 7.804/11.264 secs] [Times: user=2.13 sys=0.06, real=1.13 secs]
36314.903: [CMS-concurrent-preclean-start]
36314.963: [CMS-concurrent-preclean: 0.037/0.060 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
36314.963: [CMS-concurrent-abortable-preclean-start]
36315.195: [GC 36315.195: [ParNew: 428092K->40832K(471872K), 1.1705760 secs] 2284414K->1897153K(3093312K), 1.1710560 secs] [Times: user=0.13 sys=0.02, real=0.12 secs]
CMS: abort preclean due to time 36320.059: [CMS-concurrent-abortable-preclean: 0.844/5.095 secs] [Times: user=0.74 sys=0.05, real=0.51 secs]
36320.062: [GC[YG occupancy: 146166 K (471872 K)]36320.062: [Rescan (parallel), 1.54078550 secs]36321.603: [weak refs processing, 0.0042640 secs] [1 CMS-remark: 1856321K(2621440K)] 2002488K(3093312K), 1.5456150 secs] [Times: user=0.18 sys=0.03, real=0.15 secs]
36321.608: [CMS-concurrent-sweep-start]
36324.650: [CMS-concurrent-sweep: 2.686/3.042 secs] [Times: uesr=0.66 sys=0.02, real=0.30 secs]
36324.651: [CMS-concurrent-reset-start]
36324.700: [CMS-concurrent-reset: 0.050/0.050 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

E questo è tutto; la riga successiva sarà il prossimo ParNew GC.

Quando si forza un GC utilizzando jmap -histo: dal vivo, abbiamo invece otteniamo:

48004.088: [CMS-concurrent-mark: 8.012/8.647 secs] [Times: user=1.15 sys=0.02, real=0.87 secs]
(concurrent mode interrupted)

seguito da ~ 125 linee del modulo sottostante: (alcuni GeneratedMethodAccessor, alcuni GeneratedSerializationConstructorAccessor, alcuni GeneratedConstructorAccessor, etc)

[Unloading class sun.reflect.GeneratedMethodAccessor3]

seguito da:

: 1911295K->562232K(2621440K), 15.6886180 secs] 2366440K->562232K(3093312K), [CMS Perm: 52729K->51864K(65536K)], 15.6892270 secs] [Times: user=1.55 sys=0.01, real=1.57 secs]

Grazie in anticipo!

È stato utile?

Soluzione

com.sun.jmx.remote.util.OrderClassLoader è utilizzato nello strato remote'ing per JMX e una rapida revisione del codice suggerisce vengono creati come parte del processo di unmarshalling per le richieste remote all'interno della JVM. La durata di questi classloader sarà direttamente correlata alla durata della cosa che era deserializzati tale che una volta che non ci sono più alcun riferimento a che cosa potrebbe essere rilasciato il programma di caricamento classe.

I non sarebbe sorpreso se in questo caso la presenza di questi casi è stato un risultato diretto di voi utilizzando JConsole per esaminare quello che succede nella JVM. E sembra che avevano appena essere ripuliti dal GC come parte del normale funzionamento.

credo che sia possibile c'è un bug nell'implementazione JMX (sembra improbabile in un tempo relativamente up-to-date JVM) o forse avete alcuni MBean personalizzati o stanno utilizzando alcuni strumenti di JMX personalizzati che sono la causa del problema. Ma alla fine, Sono sospettare l'OrderClassLoader è probabilmente un rosso-aringhe e le bugie problema altrove (rotto GC o qualche altro di perdite).

Altri suggerimenti

  

Note tecniche: stiamo correndo Sun JDK   1.6.0_07, a 32 bit, su una macchina Linux 2.6.9. Aggiornamento alla versione JDK non è   davvero un'opzione, a meno che non c'è un   inevitabile, ragione principale.

Diverse versioni più recenti di Java hanno avuto aggiornamenti al garbage collector CMS. In particolare 6u12, 6u14 e 6u18.

Io non sono un esperto con GC roba, ma sto cercando di indovinare le correzioni PreClean in 6u14 possono risolvere il problema che stai vedendo. Naturalmente, potrei dire la stessa cosa di 6u18 di bug di classe scarico. Come ho detto, io non sono un esperto di GC roba.

Ci sono le correzioni per:

  • 6u10: (colpisce 6u4 +) CMS mai cancella referenti quando -XX: + ParallelRefProcEnabled
  • 6u12: CMS: codifica errata di array di oggetti sorvolati durante concomitante prepulitura
  • 6u12: CMS: gestione degli overflow non corretto quando si utilizza simultaneo parallelo marcatura
  • 6u14: CMS: errore di asserzione "is_cms_thread == Discussione :: corrente () -> is_ConcurrentGC_thread ()"
  • 6u14: CMS: CMSInitiatingPermOccupancyFraction Necessità di perm, divorziare da CMSInitiatingOccupancyFraction
  • 6u14: CMS assert: _concurrent_iteration_safe_limit aggiornamento mancato
  • 6u14: CMS: gestione degli overflow non corretto durante la prepulitura delle liste di riferimento
  • 6u14: SIGSEGV o (! Is_null (v), "Valore oop non possono mai essere zero") asserzione durante l'esecuzione con CMS e COOPs
  • 6u14: CMS:. Livelock in CompactibleFreeListSpace :: BLOCK_SIZE ()
  • 6u14: Fare lavoro CMS con compressa oops
  • 6u18: CMS: core dump con -XX: + UseCompressedOops
  • 6u18: CMS: bug relativi alla classe di scarico
  • 6u18: CMS: ReduceInitialCardMarks non sicuri in presenza di cms prelavaggio
  • 6u18: [Regressione] XX: NewRatio con -XX: + UseConcMarkSweepGC provoca errore fatale
  • 6u20: segni di carte possono essere rinviati troppo lungo

In aggiunta a quanto sopra, 6u14 introdotto anche G1 garbage collector, anche se è ancora in fase di test. G1 è destinato a sostituire CMS in Java 7.

G1 può essere utilizzato in Java 6u14 e più recente con la seguente riga di comando:

-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

Vorrei iniziare con qualcosa di molto più semplice, come:

-server -Xms3072m -Xmx3072m -XX:+UseParallelOldGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 

E vedere se questo soddisfa le vostre esigenze.

Sembra che si sta costruendo oggetti che ai loro proprietari (punti da A a B a punti A) punto. Ciò comporta il riferimento conta maggiore di zero rimanenti, in modo che il garbage collector non li può pulire. È necessario rompere il ciclo quando li si rilascia. Annullando il riferimento A o B risolverà il problema. Questo funziona anche negli sguardi di riferimento più grandi come (A -> B -> C -> D -> A). Vettori e array di oggetti possono essere utilizzati dai vostri HashMaps.

Il presense dei caricatori remoti può indicare un difetto di pulizia e chiudere riferimenti a oggetti caricati tramite JNDI o altro metodo di accesso remoto.

EDIT: ho preso un secondo sguardo alla vostra ultima riga. Si consiglia di aumentare l'allocazione perm.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top