La programmazione non è solo scrivere codice in un editor. È l'intero processo da quando prepariamo il progetto, scriviamo lo pseudo-codice e lo convertiamo in codice fino a quando lo compiliamo ed eseguiamo il debug e verifichiamo che, in effetti, funzioni correttamente. Tutti questi passaggi sono importanti all'interno di un progetto. Ma uno di quelli di cui sappiamo meno come funzionano, ei diversi tipi che esistono è l'ultimo, la compilation. Ed è questo che impareremo oggi.
Che cos'è la compilazione?

A meno che non stiamo programmando in binario, o in un linguaggio di livello molto molto basso, come l'assemblatore, le macchine non capiscono le righe di codice che scriviamo. E più alto è il livello del linguaggio che usiamo, più naturale sarà per noi, ma più complesso sarà per la macchina. Ed è per questo che, per convertire il nostro linguaggio di alto livello in linguaggio macchina, dobbiamo compila il codice .
La compilazione del codice è il processo mediante il quale convertiamo le nostre righe di codice di alto livello in linguaggio macchina. Per fare ciò è necessario disporre da un lato di un file di testo in chiaro con tutto il codice, e dall'altro di un programma, il compilatore , che è responsabile della conversione di ciascuna riga di codice in binario o nel corrispondente linguaggio di basso livello.

Grazie all'utilizzo di questi compilatori, la programmazione è molto semplice, e lo stesso codice può essere utilizzato, con qualche accorgimento, su diversi tipi di macchine. Inoltre, poiché questi programmi sono ottimizzati per funzionare su architetture specifiche, tendono a offrire buone prestazioni complessive. Tuttavia, non tutti i vantaggi. Un programma compilato funzionerà solo sulla macchina per la quale è progettato il compilatore, ad esempio un x64 CPU or ARM processore. È inoltre necessario compilare lo stesso programma più volte a seconda dei sistemi operativi (Windows, Mac OS, Linux, Android, iOS, ecc.) dove lo eseguiremo.
Differenze con l'interprete
interpreti vengono creati proprio per risolvere i due problemi che abbiamo appena visto nei compilatori. Questi sono programmi che vengono eseguiti tra il nostro codice originale e la nostra macchina e sono responsabili dell'interpretazione di ciascuna delle istruzioni a seconda della macchina o del sistema operativo in cui la stiamo eseguendo.
Questi interpreti sono posizionati nello stesso punto in cui i compilatori inizierebbero a tradurre il codice. Pertanto, eliminano tutte le limitazioni del sistema operativo o della piattaforma, potendo utilizzare lo stesso codice per tutto.
Certo, non possiamo pensare che un interprete sia perfetto. La prima cosa da tenere a mente è che questi non sono validi per tutti i tipi di linguaggi di programmazione. Gli interpreti possono funzionare, ad esempio, con Python o JavaScript, ma non sarebbero utilizzabili in altri linguaggi, come C++. Inoltre, dover interpretare il codice nello stesso momento in cui viene eseguito implica una notevole perdita di prestazioni, dovendo tradurre e gestire ogni istruzione come se fosse un compilatore separato.
Ed è qui che entrano in gioco i compilatori JIT.
Che cos'è un compilatore Just-In-Time
Mentre un normale compilatore è responsabile della compilazione di tutto il codice quando eseguiremo il programma, convertire il codice in binario e generare l'eseguibile, il compilatore JIT ottimizza questo lavoro compilando solo il codice di ciascuna funzione quando necessario. .
In questo modo, quando andremo ad eseguire un programma, il Just-In-Time, o JIT, il compilatore compilerà solo le funzioni che verranno utilizzate in quel momento, salvando il risultato in una cache. Quando usiamo il programma, quando ci imbattiamo in una nuova funzione che non è stata ancora compilata, viene compilata di nuovo. Ma quando troviamo una funzione che è già stata utilizzata, invece di compilarla nuovamente, viene cercata nella cache, risparmiando una notevole quantità di tempo.
Alcuni esempi di utilizzo compilatori JIT sono come segue:
- Java: la macchina virtuale Java, JVM, utilizza Just-In-Time.
- .NET Framework: l'ambiente di programmazione di Microsoft.
- C#: CLR (Common Language Runtime).
- Android: se utilizzato con DVM (Dalvik Virtual Machine) o ART (Android RunTime).
- Emulatori: questi compilatori vengono utilizzati anche negli emulatori per console e altri PC. Questo è il modo in cui il codice macchina viene tradotto da un'architettura CPU a un'altra.

Questi tipi di compilatori hanno prestazioni migliori degli interpreti , poiché, invece di interpretare tutto il codice, compilano ciò di cui hanno bisogno quando ne hanno bisogno. Tuttavia, dover compilare il codice in fase di runtime ha un impatto, in misura maggiore o minore, sulle prestazioni rispetto all'utilizzo di un compilatore standard che genera il binario e ci consente di eseguirlo direttamente sulla macchina. E più grande è il programma che stiamo cercando di eseguire, maggiore è l'impatto sulle prestazioni. Ciò fa sì che alcuni programmi molto grandi richiedano fino a un minuto per eseguire le prime funzioni.
Per ridurre questo impatto ci sono alcuni pre-compilatori , come MicrosoftGeneratore di immagini nativo di (Ngen) , che si occupano di eliminare i tempi di esecuzione e di far funzionare il compilatore JIT fin dall'inizio.
Inoltre, poiché la compilazione Just-In-Time utilizza principalmente dati eseguibili, proteggendoli da potenziali exploit è una grande sfida per gli sviluppatori. La memoria deve essere osservata da vicino e protetta con tecniche di sicurezza avanzate, come l'isolamento, per evitare di correre rischi inutili.
Ottimizza il compilatore JIT (Just-In-Time)
A seconda del tipo di compilatore che utilizziamo, è possibile trovare diversi livelli di ottimizzazione del codice. Ad esempio, nel caso di ApriJ9 (Compilatore Eclipse JIT per il codice Java ), è possibile scegliere il livello di ottimizzazione del codice che si desidera. Maggiore è l'ottimizzazione del compilatore Just-In-Time, più veloce sarà l'esecuzione del codice sul nostro computer, ovviamente al costo di un utilizzo molto maggiore di RAM e CPU.
Inoltre, questi compilatori sono progettati per analizzare e tracciare le funzioni di un programma e rilevare quali sono le più ripetute. Pertanto, vengono applicate alcune ottimizzazioni e quali sono chiamate meno, lasciandole un po' in secondo piano per evitare un uso non necessario delle risorse.