Perché la cache JIT non ha compilato il codice?

L’implementazione canonica JVM di Sun applica un’ottimizzazione piuttosto sofisticata al bytecode per ottenere velocità di esecuzione near-native dopo che il codice è stato eseguito alcune volte.

La domanda è, perché non è questo codice compilato memorizzato su disco per l’uso durante gli usi successivi della stessa funzione / class?

Allo stato attuale, ogni volta che viene eseguito un programma, il compilatore JIT riprende in modo nuovo, invece di usare una versione precompilata del codice. L’aggiunta di questa funzione non aggiungerebbe una spinta significativa al tempo di esecuzione iniziale del programma, quando il bytecode viene essenzialmente interpretato?

Senza ricorrere al cut’n’paste del link che @MYYN ha pubblicato, ho il sospetto che ciò sia dovuto al fatto che le ottimizzazioni eseguite da JVM non sono statiche, ma piuttosto dinamiche, basate sui pattern di dati e sui pattern di codice. È probabile che questi modelli di dati cambieranno durante la vita dell’applicazione, rendendo le ottimizzazioni memorizzate nella cache meno che ottimali.

Quindi avresti bisogno di un meccanismo per stabilire se le ottimizzazioni salvate fossero ancora ottimali, a quel punto potresti anche re-ottimizzare al volo.

La JVM di Oracle è effettivamente documentata per farlo, citando Oracle,

il compilatore può sfruttare il modello di risoluzione di class di Oracle JVM per opporre facoltativamente i metodi Java compilati attraverso chiamate, sessioni o istanze di database. Tale persistenza evita il sovraccarico di ricompilazioni inutili tra sessioni o istanze, quando è noto che semanticamente il codice Java non è cambiato.

Non so perché tutte le sofisticate implementazioni VM non offrono opzioni simili.

Un aggiornamento alle risposte esistenti – Java 8 ha un JEP dedicato alla soluzione di questo:

=> JEP 145: codice compilato cache . Nuovo link

Ad un livello molto alto, il suo objective dichiarato è :

Salvare e riutilizzare il codice nativo compilato dalle esecuzioni precedenti per migliorare il tempo di avvio di applicazioni Java di grandi dimensioni.

Spero che questo ti aiuti.

Excelsior JET ha un compilatore JIT con memorizzazione nella cache dalla versione 2.0, rilasciato nel 2001. Inoltre, il compilatore AOT può ricompilare la cache in una singola DLL / object condiviso utilizzando tutte le ottimizzazioni.

Non conosco le reali ragioni, non essendo in alcun modo coinvolto nell’implementazione della JVM, ma posso pensare ad alcune plausibili:

  • L’idea di Java è di essere un linguaggio write-once-run-anywhere, e mettere le cose precompilate nel file di class è come violare (solo “tipo di” perché ovviamente il codice byte attuale sarebbe ancora lì)
  • Aumenterebbe le dimensioni del file di class perché avresti lo stesso codice più volte, specialmente se ti capita di eseguire lo stesso programma in più JVM diverse (cosa non molto rara, quando consideri le diverse versioni come JVM diverse, che tu davvero da fare)
  • Gli stessi file di class potrebbero non essere scrivibili (anche se sarebbe abbastanza facile controllarli)
  • Le ottimizzazioni JVM sono parzialmente basate su informazioni di runtime e su altre esecuzioni potrebbero non essere applicabili (anche se dovrebbero comunque fornire alcuni vantaggi)

Ma credo davvero, e come puoi vedere, non penso che nessuno dei miei motivi sia un vero ostacolo. Immagino che Sun non consideri questo supporto come una priorità, e forse il mio primo motivo è vicino alla verità, poiché fare questo abitualmente potrebbe anche indurre le persone a pensare che i file di class Java abbiano davvero bisogno di una versione separata per ogni VM invece di essere piattaforms.

Il mio modo preferito sarebbe in realtà di avere un traduttore separato da bytecode a nativo che potreste usare per fare qualcosa del genere in modo esplicito, creando file di class che sono costruiti esplicitamente per una VM specifica, con possibilmente il bytecode originale in essi in modo da può funzionare anche con diverse VM. Ma questo probabilmente deriva dalla mia esperienza: ho fatto principalmente Java ME, dove fa davvero male che il compilatore Java non sia più intelligente sulla compilazione.