2012-01-09 17 views
5

Per un progetto, abbiamo bisogno di un modo per eseguire script utente che possono venire con file JAR allegati con classi aggiuntive.Come posso testare l'unità GC?

Quali sono le mie opzioni quando voglio scrivere un paio di test per assicurarmi che il normale script non lasci dietro qualcosa di penzoloni?

Ho specificamente bisogno di sapere: tutte le classi dei JAR allegati sono "scaricate"?

Nota: non sto cercando la soluzione super-impermeabile al 100% che funzioni su tutte le versioni di Java dalla 1.0 alla 7. In questo momento, devo solo essere migliore di "Non ne ho idea".

+0

Perché dovrebbero essere scaricati? Intendi dire che le loro istanze saranno GCed, cioè il codice e le librerie degli script utente non hanno perdite di memoria? Li stai caricando con un nuovo caricatore di classe? –

+0

Sì. Quello che mi piacerebbe è un modo per chiedere al GC "potresti presentare questa istanza in questo momento?" O forse "dimmi quanti riferimenti esistono ad esempio' foo' ". Come fanno i profiler? –

risposta

3

L'opzione migliore è quella di assicurarsi che i jar caricati siano caricati da un caricatore di classe specifico e quindi di ignorare quel caricatore di classe (dopo aver scartato tutti gli oggetti).

Per quanto riguarda il test dell'unità di scarico, se si utilizza questa opzione, è necessario estendere il framework di test e i caricatori di classi personalizzati per ottenere il flag "crea un class loader su richiesta". Quindi si carica la classe una volta con il flag attivo, si elimina il caricatore di classi e si tenta di caricare nuovamente la classe con la bandiera disattivata. Se la classe non è realmente raggiungibile, il secondo tentativo dovrebbe generare un'eccezione non trovata nella classe. Quindi esegui il wrapping dei test delle unità per passare se rientrano nell'eccezione e falliscono se riescono a colpire la linea dopo il secondo tentativo di caricamento.

Se si è disposti a utilizzare più di strumenti puramente Java, un contenitore OSGi potrebbe essere una considerazione. La maggior parte delle implementazioni del contenitore OSGi stabilite verifica esplicitamente lo scaricamento della classe.

+0

+1 per la seconda opzione.Per essere sicuri al 100% (che so non è il requisito), probabilmente dovresti eseguire il caricatore di classi con un gestore della sicurezza (per garantire che gli script non abbiano creato thread, ecc.). –

+0

@Sean Reilly, grazie. Le altre opzioni sono diventate di disturbo, quindi ho spostato il messaggio più vicino alla cima. –

+0

Il punto della domanda sembra essere che Aaron sta già facendo quello che descrivi nel tuo primo paragrafo, ma dal momento che non puoi scartare esplicitamente gli oggetti Java, vuole un modo per verificare se sta effettivamente accadendo implicitamente o se c'è una perdita. –

3

Non proverei a testare l'unità. Invece, eseguirò la JVM con -XX: -TraceClassUnloading e cercherò di vedere se le classi in questione appaiono nell'output di trace.

1

Questo dipende interamente dal modo in cui si consente l'esecuzione degli script. Hanno accesso alle classi del resto dell'applicazione?

Il modo tipico di perdita di memoria in Java è di avere un riferimento statico. Un riferimento statico è statico solo nel ClassLoader della classe che lo contiene. Quindi, se carichi gli script utente usando un ClassLoader gestito da te stesso (e dovresti farlo comunque), allora i riferimenti (statici o non) all'interno saranno eleggibili per GC non appena il classloader stesso.

L'unico modo per aggirare questo problema è aggiungere un riferimento a uno dei loro oggetti in uno dei tuoi. Quindi devi stare molto attento con l'API che esponi. Un altro modo è se farebbero un riferimento statico alla loro classe in una classe da un altro ClassLoader.

Non vedo un modo per automatizzare completamente i test per questo. Ma suppongo che potresti tracciare lo scarico della classe con qualsiasi profiler decente.

2

Sembra che ciò che si desidera testare sia che gli script del flessibile non hanno uno classloader leak.

Per fare questo, mi piacerebbe creare un WeakReference al ClassLoader utilizzato per caricare quel vaso, quindi eseguire lo script, quindi chiamare System.gc() e poi assertNull(reference.get())

+0

un'alternativa potrebbe essere quella di creare un'istanza di URLClassLoader per JAR e usarla per caricare le classi. Cestino (impostato su null) una volta fatto. – aishwarya

+1

@aishwarya: non è affatto una "alternativa". Non puoi "cestinare" oggetti java. Se si imposta il riferimento su null, l'oggetto viene raccolto automaticamente se non ci sono altri riferimenti. Quello che descrivo è come testare che l'oggetto * è stato * effettivamente raccolto. I classloader sono notoriamente difficili da eliminare perché un riferimento a un oggetto di una delle classi caricate nascosta in una raccolta somwhere è sufficiente per impedire al programma di caricamento classi e a tutte le classi caricate attraverso di esso di essere garbage collector. –