2012-09-13 14 views
6

Ho un problema divertente: se la mia applicazione viene eseguita per un lungo periodo (> 20h), a volte viene visualizzato errore NoClassDefFound - sembra che JVM abbia deciso che la classe non verrà usato comunque e GCd esso.Classi mancanti se l'applicazione viene eseguita a lungo

Per essere un po 'più specifico, ecco un esempio di caso:

object ErrorHandler extends PartialFunction[Throwable,Unit] { 
    def isDefinedAt(t: Throwable) = true 
    def apply(e: Throwable) =e match { 
    // ... handle errors 
    } 
} 

// somewhere else in the code... 
try { 
    // ... long running code, can take more than 20 hours to complete 
} catch (ErrorHandler) 

e ottengo la seguente eccezione:

Exception in thread "main" java.lang.NoClassDefFoundError: org/rogach/avalanche/ErrorHandler$ 

Se quella prova/piste blocco catch per piccole quantità di tempo, tutto funziona come previsto.

Se qualcuno è interessato, qui è la base di codice in questione: Avalanche

ho bisogno di sottolineare che ho visto questo e problemi simili solo su Cent OS 5 macchine, utilizzando JRE 6u26 e Scala 2.9.1/2.9.2.

Quale potrebbe essere la causa di questo problema?

+4

Provare a eseguirlo con '-XX: -TraceClassUnloading'. Quali sono i risultati? http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html – ron

+0

@ron - Ci sto provando in questo momento, ma ci vorrà del tempo :) E il file di registro è piuttosto lungo e verboso, per quali parole dovrei grep per ottenere l'output di tracciamento? – Rogach

+0

non si può indovinare con gli occhi bendati, ma il nome della classe sotto sospetto è un candidato sicuro :) – ron

risposta

1

Se si esaurisce la memoria cercando di inizializzare una classe, si suppone che si visualizzerà OutOfMemory o NoClassDef?

//from initialize_impl 
    if (NULL == message) { 
    // Out of memory: can't create detailed error message 
    THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className); 

È possibile che il codice abbia gettato OOM, quindi non è stato possibile caricare l'oggetto gestore di eccezioni.

Esistono, naturalmente, altre possibili condizioni transitorie: la rete era inattiva e la classe si trova su un'unità in rete; o hai pulito la directory delle classi durante il test. Un'altra possibilità è che tu abbia costruito la tua app su un file system senza distinzione tra maiuscole e minuscole e stia testando su un file system sensibile al maiuscolo/minuscolo con un file di classe con nome anomalo. Ad esempio, se si modifica l'oggetto "gestore" in "gestore" senza eliminare * .class, verrà comunque visualizzato "Handler.class". (Ma ho il sospetto che il dettaglio del messaggio di errore includa il conflitto di nomi, a meno che tu non sia OOM, ovviamente.)

Non ho avuto la possibilità di provare a interrompere AbstractFileClassLoader; la mia speculazione precedente segue:

Vale la pena spiegando che Avalanche è un tool di creazione, e si esegue un'istanza di scalac per compilare il build.scala a un classfile in memoria che viene caricato con AbstractFileClassLoader di scalac, dove "AbstractFile" è l'astrazione. Dato che qualsiasi build.scala muck con la configurazione dello strumento, ovviamente è essenziale che AFCL rispetti la delega del classloader. Sembra vero, ma noto che non si delega prima ai genitori su getResourceAsStream (come conferma rapida). La cosa sospetta è che findClass usa classBytes, che in caso di fallimento chiama super, che è il bello ScalaClassLoader, ma che usa getResourceAsStream per caricare Foo.class. Quindi chiamare findClass potrebbe restituire una classe dal genitore CL (che è errato), anche se potrebbe essere discutibile se il genitore è già noto che ha già fallito. Perché è il cuore della mia notte, non posso trarre una conclusione, ma vorrei inchiodarla se il mio strumento di costruzione si basava su questo comportamento.

Non so cosa ci sia nel tuo build.scala (o av.scala) che funziona per un giorno, ma forse hai Avalanche (ri) caricato da un bambino che fa il buffo classloader, poi quando lancia, il CL non riesce a classificare il tuo ErrorHandler.

+0

Beh, potresti avere ragione, ma io ho osservato un comportamento simile in altre due situazioni, in cui non mi sono comportato male con i programmi di caricamento di classi e il tema che unisce tutti questi casi sembra essere una funzione parziale: – Rogach

+0

Non conosco quasi nulla sui programmi di caricamento classi, ma viene utilizzato 'AbstractFileClassLoader' (penso) solo per caricare la classe 'Build' e tutte le altre classi devono passare attraverso il classloader predefinito oppure esiste un meccanismo in base al quale il classloader figlio può iniziare a sostituire il padre? – Rogach

Problemi correlati