Perché la cache JVM non ha compilato il codice JIT?


107

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

La domanda è: perché questo codice compilato non viene memorizzato nella cache su disco per essere utilizzato durante gli usi successivi della stessa funzione / classe?

Allo stato attuale, ogni volta che viene eseguito un programma, il compilatore JIT ricomincia da capo, invece di utilizzare una versione precompilata del codice. L'aggiunta di questa funzionalità non aggiungerebbe un aumento significativo al tempo di esecuzione iniziale del programma, quando il bytecode viene essenzialmente interpretato?


4
Un thread che discute di questo problema: javalobby.org/forums/thread.jspa?threadID=15812
miku

2
Ma una domanda improbabile per attirare una risposta definitiva.
bmargulies

1
Non sono sicuro di un aumento "significativo", perché allora dovresti caricare cose JITted dal disco invece di JITing in memoria. Potrebbe accelerare le cose, ma caso per caso.
R. Martinho Fernandes

1
Grazie per le ottime risposte a tutti! Tutte le risposte erano ugualmente valide, quindi sono andato con la comunità su questo ...
Chinmay Kanchi

Questa è una buona domanda se me lo chiedi :)
Alfred

Risposte:


25

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

Quindi avresti bisogno di un meccanismo per stabilire se le ottimizzazioni salvate erano ancora ottimali, a quel punto potresti anche riottimizzare al volo.


6
... oppure potresti semplicemente offrire la persistenza come opzione , come fa la JVM di Oracle: consente ai programmatori avanzati di ottimizzare le prestazioni delle loro applicazioni quando e dove sanno che i modelli non cambiano, sotto la loro responsabilità. Perchè no?!
Alex Martelli

2
Perché probabilmente non ne vale la pena. Se né SUN, né IBM né BEA hanno ritenuto utile per le loro JVM di prestazioni, ci sarà una buona ragione per questo. Forse la loro ottimizzazione RT è più veloce di quella di Oracle, motivo per cui Oracle la memorizza nella cache.
skaffman

9
Perché non prendere le ottimizzazioni memorizzate come punto di partenza, per utilizzare ciò che è stato appreso nelle corse precedenti? Da lì JIT potrebbe funzionare come al solito per riottimizzare le cose. All'arresto, il codice potrebbe essere nuovamente persistente ed essere utilizzato nell'esecuzione successiva come nuovo punto di partenza.
Puce

1
@Puce L'unico motivo a cui posso pensare è che AFAIK non si ottengono statistiche di profilazione dall'esecuzione di codice ottimizzato. Quindi non avresti modo di migliorare ...
maaartinus

1
Personalmente starei bene con un'opzione "mantieni solo le informazioni di profilazione JIT tra le esecuzioni" con tutti gli avvertimenti che "questo sarà valido solo con la stessa identica JVM, gli stessi dati ecc. E altrimenti ignorato". Per quanto riguarda il motivo per cui ciò non è stato implementato, mi sarei aspettato che la complessità aggiuntiva del persistere e della convalida dei dati iniziali JIT fosse eccessiva per prendere risorse da altri progetti. Data la scelta tra questo e i flussi lambda + Java 8 preferirei avere quest'ultimo.
Thorbjørn Ravn Andersen

25

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

il compilatore può trarre vantaggio dal modello di risoluzione delle classi di Oracle JVM per rendere eventualmente persistenti i metodi Java compilati tra le chiamate, le sessioni o le istanze del database. Tale persistenza evita il sovraccarico di ricompilazioni non necessarie tra sessioni o istanze, quando è noto che semanticamente il codice Java non è cambiato.

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


8
Perché altre JVM sofisticate non hanno un RDBMS di grande impresa a portata di mano per archiviare cose in :)
skaffman

Wow! ciò significa che le compilation a volte vengono memorizzate nella cache. Questa è una buona notizia!
Sandeep Jindal

Anche J9 di IBM è documentato per farlo.
user314104

9
Si noti che questa Oracle JVM è quella all'interno del database Oracle, non il download che Oracle ha ottenuto con l'acquisto di Sun.
Thorbjørn Ravn Andersen


5

Excelsior JET ha un compilatore JIT per la memorizzazione nella cache dalla versione 2.0, rilasciata nel 2001. Inoltre, il suo compilatore AOT può ricompilare la cache in un singolo oggetto DLL / condiviso utilizzando tutte le ottimizzazioni.


3
Sì, ma la domanda riguardava la JVM canonica, ovvero la JVM di Sun. Sono ben consapevole che ci sono diversi compilatori AOT per Java e altre JVM di memorizzazione nella cache.
Chinmay Kanchi

0

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

  • L'idea di Java è di essere un linguaggio che si scrive una sola volta e che si esegue ovunque, e inserire materiale precompilato nel file di classe è una specie di violazione (solo "un po '" perché ovviamente il codice byte effettivo sarebbe ancora lì)
  • Aumenterebbe le dimensioni del file di classe perché avresti lo stesso codice lì più volte, specialmente se ti capita di eseguire lo stesso programma su più JVM diverse (il che non è davvero raro, se consideri versioni diverse come JVM diverse, che tu devo davvero fare)
  • I file di classe stessi potrebbero non essere scrivibili (anche se sarebbe abbastanza facile verificarlo)
  • Le ottimizzazioni JVM sono parzialmente basate su informazioni di runtime e su altre esecuzioni potrebbero non essere applicabili (sebbene dovrebbero comunque fornire qualche vantaggio)

Ma sto davvero indovinando, e come puoi vedere, non penso che nessuna delle mie ragioni sia un vero e proprio spettacolo. Immagino che Sun non consideri questo supporto come una priorità, e forse la mia prima ragione è vicina alla verità, poiché farlo abitualmente potrebbe anche portare le persone a pensare che i file di classe Java abbiano davvero bisogno di una versione separata per ogni VM invece di essere piattaforme.

Il mio modo preferito sarebbe effettivamente avere un traduttore da bytecode a nativo separato che potresti usare per fare qualcosa di simile esplicitamente in anticipo, creando file di classe che sono esplicitamente costruiti per una specifica VM, con possibilmente il bytecode originale in essi in modo che tu può essere eseguito anche con diverse VM. Ma probabilmente questo deriva dalla mia esperienza: ho principalmente fatto Java ME, dove fa davvero male che il compilatore Java non sia più intelligente della compilazione.


1
c'è un posto nel file di classe per queste cose, infatti quello era l'intento originale (memorizzare il codice JIT'ed come un attributo nel file di classe).
TofuBeer

@TofuBeer: grazie per la conferma. Sospettavo che potesse essere il caso (è quello che avrei fatto), ma non ne ero sicuro. Modificato per rimuoverlo come possibile motivo.
JaakkoK

Penso che tu abbia colpito nel segno con il tuo ultimo punto di proiettile. Gli altri potrebbero essere aggirati, ma l'ultima parte è, penso, la ragione principale per cui il codice JITed non viene persistito.
Sasha Chedygov

1
L'ultimo paragrafo circa il compilatore esplicito bytecode-to-native è quello che si ha attualmente in .NET con NGEN ( msdn.microsoft.com/en-us/library/6t9t5wcf(VS.71).aspx ).
R. Martinho Fernandes
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.