{"id":35851,"date":"2019-10-31T22:07:03","date_gmt":"2019-10-31T19:07:03","guid":{"rendered":"https:\/\/prohoster.info\/blog\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\/"},"modified":"2019-10-31T22:07:03","modified_gmt":"2019-10-31T19:07:03","slug":"bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","title":{"rendered":"Una lunga intervista con Cliff Click, il padre della JIT compilation in Java","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Una lunga intervista con Cliff Click, il padre della JIT compilation in Java\" src=\"\/wp-content\/uploads\/2019\/07\/9ea9740ef74c0ae14d334482af115222.png\" style=\"display:block;margin: 0 auto;\" \/><strong>Cliff Click<\/strong> \u2014 CTO dell'azienda Cratus (sensori IoT per migliorare i processi), fondatore e cofondatore di diverse startup (tra cui Rocket Realtime School, Neurensic e H2O.ai) con diversi exit di successo. Cliff scrisse il suo primo compilatore all'et\u00e0 di 15 anni (Pascal per TRS Z-80)! \u00c8 pi\u00f9 conosciuto per il suo lavoro su C2 in Java (the Sea of Nodes IR). Questo compilatore ha dimostrato al mondo che JIT pu\u00f2 produrre codice di qualit\u00e0, diventando uno dei fattori chiave che hanno reso Java una delle principali piattaforme software moderne. In seguito, Cliff ha aiutato l'azienda Azul Systems a costruire un mainframe a 864 core con software in pura Java, che supportava pause GC su un heap da 500 gigabyte in meno di 10 millisecondi. In generale, Cliff ha avuto l'opportunit\u00e0 di lavorare su tutti gli aspetti della JVM.<br clear=\"all\"><br \/>\n\u00a0<br \/>\nQuesto post di Hubra \u00e8 una lunga intervista con Cliff. Parleremo dei seguenti argomenti:<\/p>\n<p><\/p>\n<ul>\n<li>Passaggio a ottimizzazioni a basso livello<\/li>\n<li>Come fare un grande refactoring<\/li>\n<li>Modello di costo<\/li>\n<li>Formazione su ottimizzazioni a basso livello<\/li>\n<li>Esempi pratici di miglioramento delle prestazioni<\/li>\n<li>Perch\u00e9 creare un proprio linguaggio di programmazione<\/li>\n<li>Carriera di ingegnere delle prestazioni<\/li>\n<li>Sfide tecniche<\/li>\n<li>Qualche nota sull'allocazione dei registri e sulla multithreading<\/li>\n<li>La sfida pi\u00f9 grande della vita<\/li>\n<\/ul>\n<p><\/p>\n<p>Intervistatori:<\/p>\n<p><\/p>\n<ul>\n<li><strong>Andrey Satarin<\/strong> di Amazon Web Services. Nella sua carriera ha lavorato a progetti molto diversi: ha testato un database distribuito NewSQL in Yandex, un sistema di rilevamento basato su cloud presso Kaspersky Lab, un gioco multiplayer in Mail.ru e un servizio di calcolo dei prezzi delle valute in Deutsche Bank. \u00c8 interessato al testing di sistemi backend e distribuiti su larga scala.<\/li>\n<li><strong>, che partecipa ai comitati di programma di un'incredibile quantit\u00e0 di conferenze... sembra che ora siano cinque alla volta. Anche nell'altro BOF su \u00abModern CS in real world\u00bb si discuteva di NVM e ci sono arrivati in modo completamente autonomo.<\/strong> di Netcracker. Da dieci anni si occupa di prestazioni e scalabilit\u00e0 di NetCracker OS, un software utilizzato dagli operatori di telecomunicazioni per automatizzare i processi di gestione della rete e delle apparecchiature di rete. \u00c8 appassionato di prestazioni di Java e Oracle Database. Autore di oltre una dozzina di miglioramenti delle prestazioni nel driver JDBC ufficiale di PostgreSQL.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/li>\n<\/ul>\n<p><\/p>\n<h1 id=\"perehod-k-nizkourovnevym-optimizaciyam\">Passaggio a ottimizzazioni a basso livello<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Sei una persona conosciuta nel mondo della compilazione JIT, di Java e della prestazione in generale, giusto?\u00a0<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Esattamente!<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Iniziamo con alcune domande generali sul lavoro sulle prestazioni. Cosa pensi della scelta tra ottimizzazioni ad alto livello e a basso livello come il lavoro a livello CPU?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Qui \u00e8 tutto semplice. Il codice pi\u00f9 veloce \u00e8 quello che non viene mai eseguito. Pertanto, \u00e8 sempre necessario partire da un alto livello, lavorare sugli algoritmi. Una notazione O migliore batter\u00e0 una notazione O peggiore, a meno che non intervengano delle costanti abbastanza grandi. Le questioni a basso livello vengono affrontate per ultime. Di solito, se hai ottimizzato bene tutto il resto della pila e c'\u00e8 ancora qualcosa di interessante rimasto \u2013 questo \u00e8 il basso livello. Ma come si inizia da un alto livello? Come si fa a sapere se \u00e8 stato fatto abbastanza lavoro a livello alto? Beh\u2026 non lo si sa. Non ci sono ricette pronte. Devi capire il problema, decidere cosa intendi fare (per non compiere passi non necessari in seguito) e allora puoi gi\u00e0 tirare fuori il profiler, che pu\u00f2 dirti qualcosa di utile. A un certo punto, realizzi che hai eliminato le cose superflue e che \u00e8 giunto il momento di dedicarti alla fine-tuning a basso livello. Questo \u00e8 senza dubbio una forma d'arte. Molte persone fanno cose superflue, ma si muovono cos\u00ec velocemente che non hanno tempo da dedicare alle prestazioni. Ma ci\u00f2 fino a quando la questione non diventa critica. Di solito, il 99% del tempo a nessuno importa cosa sto facendo, fino al momento in cui su un percorso critico non compare qualcosa di importante che interessa a qualcuno. Ed \u00e8 allora che tutti iniziano a chiederti<\/p>\n<p><\/p>\n<h1 id=\"kak-delat-bolshoy-refaktoring\">Come fare un grande refactoring<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Come lavori sulle prestazioni? Questo \u00e8 un problema trasversale. Ad esempio, ti \u00e8 mai capitato di affrontare problemi derivanti dall'interazione di un gran numero di funzionalit\u00e0 gi\u00e0 esistenti?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Cerco di evitarlo. Se so che le prestazioni diventeranno un problema, rifletto prima di iniziare a codificare, specialmente sulle strutture dati. Ma spesso scopri tutto ci\u00f2 molto pi\u00f9 tardi. E allora devi ricorrere a misure estreme e fare quello che definisco 'riscrivi e domina': devi prendere un pezzo abbastanza grande. Una parte del codice dovr\u00e0 comunque essere riscritta a causa di problemi di prestazioni o per qualcos'altro. Qualunque sia la ragione per riscrivere il codice, \u00e8 quasi sempre meglio riscrivere un pezzo pi\u00f9 grande piuttosto che uno pi\u00f9 piccolo. In quel momento tutti iniziano a tremare per paura: 'Oh cielo, non possiamo toccare cos\u00ec tanto codice!'. Ma, di fatto, questo approccio funziona quasi sempre molto meglio. Devi affrontare subito un grande problema, delineare un grande cerchio intorno ad esso e dire: tutto ci\u00f2 che \u00e8 dentro il cerchio lo riscriver\u00f2. Il confine \u00e8 molto pi\u00f9 piccolo del contenuto all'interno che deve essere sostituito. E se un tale tracciamento dei confini consente di lavorare all'interno in modo perfetto \u2013 hai le mani libere, fai quello che vuoi. Non appena hai capito il problema, il processo di riscrittura diventa molto pi\u00f9 semplice, quindi mordi un grosso pezzo!<br \/>\nAllo stesso tempo, quando riscrivi un grosso pezzo e capisci che le prestazioni diventeranno un problema, puoi subito iniziare a preoccupartene. Di solito questo si traduce in cose semplici come 'non copiare i dati, gestisci i dati nel modo pi\u00f9 semplice possibile, rendili pi\u00f9 piccoli'. Nelle grandi riscritture, ci sono modi standard per migliorare le prestazioni. E ruotano quasi sempre attorno ai dati.<\/p>\n<p><\/p>\n<h1 id=\"model-stoimosti\">Modello di costo<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: In uno dei podcast hai parlato dei modelli di costo nel contesto delle prestazioni. Puoi spiegare cosa intendevi?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Certo. Sono nato in un'epoca in cui le prestazioni della CPU erano estremamente importanti. E quest'era sta tornando di nuovo \u2013 il destino non \u00e8 privo di ironia. Ho cominciato a vivere ai tempi delle macchine a otto bit, il mio primo computer funzionava con 256 byte. Proprio byte. Tutto era molto piccolo. Bisognava contare le istruzioni e appena abbiamo iniziato a progredire verso linguaggi di programmazione pi\u00f9 alti, i linguaggi si sono assunti sempre di pi\u00f9. C'era l'Assember, poi il Basic, poi il C, e il C si occupava di molte pi\u00f9 dettagli, come la gestione dei registri e la scelta delle istruzioni. Ma l\u00ec tutto era abbastanza chiaro e se creavo un puntatore a un'istanza di variabile, avrei ottenuto un load, e il costo di quell'istruzione \u00e8 noto. L'hardware fornisce un numero noto di cicli macchina, quindi la velocit\u00e0 di esecuzione di diverse operazioni pu\u00f2 essere calcolata semplicemente sommando tutte le istruzioni che prevedi di eseguire. Ogni compare\/test\/branch\/call\/load\/store poteva essere sommato e si poteva dire: ecco il tempo di esecuzione. Occupandosi del miglioramento delle prestazioni, noterai sicuramente quali numeri corrispondono ai piccoli cicli caldi.\u00a0<br \/>\nMa non appena ti sposti su Java, Python e cose simili, ti allontani molto in fretta dall'hardware di basso livello. Qual \u00e8 il costo della chiamata a un getter in Java? Se il JIT in HotSpot ha fatto tutto correttamente <noindex><a rel=\"nofollow\" href=\"https:\/\/wiki.openjdk.java.net\/display\/HotSpot\/Inlining\">inlining<\/a><\/noindex>, sar\u00e0 un load, ma se non lo ha fatto \u2013 sar\u00e0 una chiamata di funzione. Poich\u00e9 la chiamata cade su un ciclo caldo, annuller\u00e0 tutte le altre ottimizzazioni in quel ciclo. Pertanto, il costo reale sar\u00e0 molto maggiore. E perdi immediatamente la capacit\u00e0 di guardare un pezzo di codice e capire se dovremmo eseguirlo in termini di frequenza di clock della CPU, memoria utilizzata e cache. Tutto ci\u00f2 diventa interessante solo se ti immergi davvero nelle prestazioni.<br \/>\nAttualmente ci troviamo in una situazione in cui le velocit\u00e0 dei processori non aumentano quasi pi\u00f9 da un decennio. I tempi antichi stanno tornando! Non puoi pi\u00f9 contare su buone prestazioni in single-thread. Ma se improvvisamente ti dedichi ai calcoli paralleli \u2013 \u00e8 incredibilmente difficile, tutti ti guardano come se fossi James Bond. I guadagni decuplicati di solito si verificano nei luoghi in cui qualcuno ha tralasciato qualcosa. La parallelit\u00e0 richiede molto lavoro. Per ottenere quel guadagno decuplicato, devi comprendere il modello di costo. Cosa e quanto costa. E per farlo, devi capire come il linguaggio si adatti all'hardware sottostante.<br \/>\nMartin Thompson ha scelto una parola fantastica per il suo blog <noindex><a rel=\"nofollow\" href=\"https:\/\/mechanical-sympathy.blogspot.com\/\">Simpatia Meccanica<\/a><\/noindex>! \u00c8 fondamentale capire cosa sta per fare l'hardware, come lo far\u00e0 e perch\u00e9 lo fa. Utilizzando queste informazioni, \u00e8 piuttosto semplice iniziare a contare le istruzioni e scoprire dove va a finire il tempo di esecuzione. Se non hai una preparazione adeguata, stai semplicemente cercando un gatto nero in una stanza buia. Vedo continuamente persone che ottimizzano le prestazioni e non hanno la minima idea di che diavolo stiano facendo. Si affannano molto e non vanno quasi da nessuna parte. E quando prendo lo stesso pezzo di codice, ci metto un paio di piccoli hack e ottengo un guadagno di cinque o dieci volte, loro dicono: beh, non \u00e8 giusto, sapevamo gi\u00e0 che eri migliore. \u00c8 straordinario. Di cosa stavo parlando\u2026 il modello di costo consiste nel sapere che tipo di codice scrivi e quanto velocemente funziona in media nel contesto generale.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: E come si fa a tenere in mente un tale volume? Si raggiunge attraverso molta esperienza, o no? Dove si acquisisce questa esperienza?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Beh, la mia esperienza l'ho acquisita non nel modo pi\u00f9 semplice. Ho programmato in Assembly quando era ancora possibile capire ogni singola istruzione. Pu\u00f2 sembrare sciocco, ma da allora ho nella mia mente, nella mia memoria, un set di istruzioni Z80. Non ricordo i nomi delle persone un minuto dopo aver parlato con loro, ma ricordo il codice scritto 40 anni fa. \u00c8 divertente, sembra un sindrome di \"<noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A1%D0%B8%D0%BD%D0%B4%D1%80%D0%BE%D0%BC_%D1%81%D0%B0%D0%B2%D0%B0%D0%BD%D1%82%D0%B0\">scienziato idiota<\/a><\/noindex>\u00bb.<\/p>\n<p><\/p>\n<h1 id=\"obuchenie-nizkourovnevym-optimizaciyam\">Formazione su ottimizzazioni a basso livello<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: C'\u00e8 un modo pi\u00f9 semplice per entrare nel settore?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: S\u00ec e no. Il ferro di cui facciamo tutti uso non \u00e8 cambiato molto nel tempo. Tutti usano x86, tranne gli smartphone basati su Arm. Se non ti occupi di qualche tipo di embedded hardcore, hai tutto lo stesso. Bene, andiamo avanti. Anche le istruzioni non sono cambiate da secoli. Devi andare a scrivere qualcosa in Assembly. Un po', ma abbastanza per iniziare a capire. Tu stai sorridendo, ma io parlo molto seriamente. Devi capire la corrispondenza tra il linguaggio e l'hardware. Dopo di che, devi andare, scrivere un po' e realizzare un piccolo compilatore giocattolo per un piccolo linguaggio giocattolo.<br \/>\nDa dove ottenere un modello di costo? Beh, si pu\u00f2 leggere qualcosa, certo... Ma penso che il modo migliore sia agire. Creare un piccolo compilatore e questo sar\u00e0 il miglior modo per comprendere il modello di costo e farlo proprio. Un piccolo compilatore, che possa essere utilizzato per programmare un forno a microonde \u2013 \u00e8 un compito da principianti. Beh, intendo dire che se hai gi\u00e0 delle abilit\u00e0 di programmazione, dovrebbero essere sufficienti. Tutte queste cose come analizzare una stringa, che sar\u00e0 qualche espressione algebrica, estrarre da essa le istruzioni delle operazioni matematiche nell'ordine corretto, prendere i valori corretti dai registri \u2013 tutto questo si fa facilmente. E mentre lo fai, si imprime nella mente. Credo che tutti sappiano cosa faccia un compilatore. E questo dar\u00e0 una comprensione del modello di costo.<\/p>\n<p><\/p>\n<h1 id=\"prakticheskie-primery-uluchsheniya-proizvoditelnosti\">Esempi pratici di miglioramento delle prestazioni<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Su cosa dovremmo prestare attenzione quando lavoriamo sulle prestazioni?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Strutture dati. A proposito, \u00e8 da un po' che non tengo queste lezioni... <noindex>Rocket School<\/noindex>. \u00c8 stato divertente, ma richiedeva cos\u00ec tanto impegno, e ho anche una vita da vivere! Va bene. Quindi, in una delle lezioni grandi e interessanti, \"Dove va la tua performance\", ho dato agli studenti un esempio: due e mezzo gigabyte di dati fintech letti da un file CSV e poi dovevamo calcolare il numero di prodotti venduti. Normali dati di mercato a ticker. Pacchetti UDP, trasformati in formato testuale, a partire dagli anni '70. Chicago Mercantile Exchange \u2013 tutte queste cose come petrolio, mais, fagioli di soia, e simili. Dovevamo contare questi prodotti, il numero di transazioni, il volume medio del movimento di fondi e beni, ecc. Questa \u00e8 una matematica commerciale piuttosto semplice: trovare il codice del prodotto (questo \u00e8 1-2 caratteri in una tabella hash), ottenere la somma, aggiungerla a uno dei set di transazioni, aggiungere il volume, aggiungere il costo e un paio di altre cose. Matematica molto semplice. La realizzazione giocattolo era molto diretta: tutto si trova in un file, leggo il file e mi muovo attraverso di esso, separando le singole registrazioni in righe Java, cercando le cose necessarie e sommando secondo la matematica descritta sopra. E funziona con una certa velocit\u00e0. <\/p>\n<p><\/p>\n<p>Con un approccio del genere, \u00e8 ovvio cosa stia succedendo, e i calcoli paralleli non aiuteranno, giusto? Si scopre che un aumento delle prestazioni di cinque volte pu\u00f2 essere ottenuto semplicemente scegliendo le strutture dati giuste. E questo sorprende anche i programmatori esperti! Nel mio caso specifico, il punto era che non si dovrebbero effettuare allocazioni di memoria nel ciclo caldo. Bene, non \u00e8 tutta la verit\u00e0, ma in generale \u2013 non dovresti allocare \"una volta ogni X\", quando X \u00e8 sufficientemente grande. Quando X \u00e8 due e mezzo gigabyte, non dovresti allocare nulla \"una volta per lettera\", o \"una volta per riga\", o \"una volta per campo\", nulla di simile. \u00c8 proprio su questo che si sprecano tempo e risorse. Come funziona tutto ci\u00f2? Immagina che io stia effettuando una chiamata <code>String.split()<\/code> o <code>BufferedReader.readLine()<\/code>. <code>Readline<\/code> crea una stringa da un insieme di byte ricevuti in rete, una volta per ogni riga, per ciascuna delle centinaia di milioni di righe. Prendo questa stringa, la analizzo e la scarto. Perch\u00e9 scarto \u2013 beh, l'ho gi\u00e0 elaborata, tutto qui. Quindi, per ogni byte letto da questi 2,7G, vengono scritti due caratteri nella stringa, ovvero gi\u00e0 5,4G, e non mi servono pi\u00f9, quindi vengono scartati. Se guardiamo alla larghezza di banda della memoria, stiamo caricando 2,7G, che passano attraverso la memoria e il bus di memoria nel processore, e poi il doppio viene inviato a una stringa in memoria, e tutto ci\u00f2 viene rielaborato quando si crea ogni nuova stringa. Ma devo leggerla, l'hardware la legge, anche se successivamente tutto verr\u00e0 rielaborato. E devo scriverla, perch\u00e9 ho creato una stringa e le cache sono piene \u2013 la cache non pu\u00f2 contenere 2,7G. Pertanto, per ogni byte letto leggo altri due byte aggiuntivi e scrivo due byte aggiuntivi, e alla fine abbiamo un rapporto di 4:1 \u2013 in questo rapporto stiamo sprecando senza motivo la larghezza di banda della memoria. E poi scopriamo che se faccio <code>String.split()<\/code> \u2013 lo faccio lontano dall'essere l'ultima volta, ci possono essere altre 6-7 particolari all'interno. Pertanto, il codice classico di lettura CSV seguito da parsing delle righe porta a perdite di larghezza di banda della memoria nell'ordine di 14:1 rispetto a ci\u00f2 che realmente desidereresti avere. Se si eliminano queste allocazioni, si pu\u00f2 ottenere un'accelerazione di cinque volte. <\/p>\n<p><\/p>\n<p>E non \u00e8 che sia molto difficile. Se guardi il codice da una prospettiva giusta, tutto diventa abbastanza semplice, non appena realizzi la sostanza del problema. Non bisogna smettere mai di allocare memoria: il problema \u00e8 solo che stai allocando qualcosa e essa muore subito, bruciando nel processo una risorsa importante, che in questo caso \u00e8 la larghezza di banda della memoria. E tutto ci\u00f2 si traduce in un abbassamento delle prestazioni. Su x86 di solito \u00e8 necessario accendere attivamente i cicli della CPU, mentre qui hai bruciato tutta la memoria molto prima. La soluzione \u00e8 ridurre il numero di allocazioni.\u00a0<br \/>\nUn'altra parte del problema \u00e8 che, se avvii un profiler quando la banda di memoria \u00e8 esaurita, proprio nel momento in cui succede, di solito ti aspetti il ritorno dalla cache, perch\u00e9 \u00e8 piena di spazzatura che hai appena generato, tutte quelle righe. Di conseguenza, ogni operazione di load o store diventa lenta, perch\u00e9 portano a Miss in cache: l'intera cache \u00e8 diventata lenta, in attesa che la spazzatura se ne vada. Quindi il profiler mostrer\u00e0 solo rumore casuale caldo, spalmato lungo tutto il ciclo: non ci sar\u00e0 nessuna istruzione calda o posizione nel codice separata. Solo rumore. E se osservi i cicli GC, saranno tutti nella Young Generation e super veloci \u2013 microsecondi o millisecondi al massimo. Infatti, tutta questa memoria muore immediatamente. Allocando miliardi di gigabyte, lui li taglia, taglia e taglia di nuovo. Tutto ci\u00f2 accade molto rapidamente. Quindi, ci sono cicli GC economici, rumore caldo lungo tutto il ciclo, ma vogliamo ottenere un incremento di 5 volte. In quel momento, qualcosa dovrebbe scattare nella tua testa e farti pensare: \u00abperch\u00e9?!\u00bb. L'overflow della banda di memoria non viene visualizzato nel debugger classico, devi avviare il debugger dei contatori di prestazione hardware e vederlo da solo e direttamente. Altrimenti, puoi sospettarlo da questi tre sintomi. Il terzo sintomo \u00e8 quando guardi cosa stai allocando, chiedi al profiler e lui risponde: \u00abHai creato un miliardo di righe, ma GC ha funzionato gratuitamente\u00bb. Non appena accade questo, capisci che hai generato troppi oggetti e bruciato tutta la larghezza di banda della memoria. C'\u00e8 un modo per capire ci\u00f2, ma non \u00e8 ovvio.\u00a0<\/p>\n<p><\/p>\n<p>Il problema \u00e8 nella struttura dei dati: una struttura nuda alla base di tutto ci\u00f2 che accade, \u00e8 troppo grande, occupa 2.7G su disco, quindi \u00e8 molto indesiderabile fare una copia di questa cosa - si desidera caricarla direttamente dal buffer di byte di rete nei registri, per non dover leggere e scrivere nella stringa cinque volte. Sfortunatamente, Java di default non ti offre una libreria del genere all'interno del JDK. Ma in fondo \u00e8 banale, vero? Fondamentalmente, si tratta di 5-10 righe di codice che serviranno a implementare il proprio caricatore di stringhe bufferizzato, che riproduce il comportamento della classe string, fungendo al contempo da involucro attorno al buffer di byte sottostante. Di conseguenza, si scopre che si lavora quasi come se si trattasse di stringhe, ma in realt\u00e0 ci sono puntatori che si muovono verso il buffer, e i byte grezzi non vengono copiati da nessuna parte, e cos\u00ec si riutilizzano gli stessi buffer, volta dopo volta, e il sistema operativo \u00e8 felice di occuparsi delle cose per cui \u00e8 progettato, come la doppia bufferizzazione nascosta di questi buffer di byte, mentre tu stesso non macini pi\u00f9 un flusso infinito di dati non necessari. A proposito, capite che quando si lavora con il GC si garantisce che ogni allocazione di memoria non sar\u00e0 visibile al processore dopo l'ultimo ciclo di GC? Quindi, tutto questo non pu\u00f2 proprio essere nella cache, e ci\u00f2 che succede dopo \u00e8 un errore garantito al 100%. Quando si lavora con un puntatore, su x86 leggere un registro dalla memoria richiede 1-2 cicli, e non appena ci\u00f2 avviene, paghi, paghi, paghi, perch\u00e9 tutta la memoria \u00e8 <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Cache_inclusion_policy\">NINE cache<\/a><\/noindex> \u2013 e questa \u00e8 la vera costo dell'allocazione della memoria. Il vero costo.<\/p>\n<p><\/p>\n<p>In altre parole, le strutture dati sono le cose pi\u00f9 difficili da cambiare. E una volta che ti sei reso conto di aver scelto la struttura dati sbagliata, che in seguito comprometter\u00e0 le prestazioni, di solito richiede un notevole lavoro per correggerla. Se non lo fai, la situazione peggiorer\u00e0. Prima di tutto, \u00e8 importante considerare le strutture dati. Il vero costo qui \u00e8 associato alle strutture dati pesanti, che tendi a usare nel modo \"ho copiato la struttura dati X nella struttura dati Y, perch\u00e9 Y mi piace di pi\u00f9 esteticamente\". Ma l'operazione di copia (che sembra economica) consuma in realt\u00e0 banda di memoria e qui si annida tutto il tempo di esecuzione perso. Se ho una gigantesca stringa JSON e voglio trasformarla in un albero DOM strutturato di POJO o qualcosa del genere, l'operazione di parsing di questa stringa e la costruzione di POJO, seguita da ulteriori accessi a POJO, comporter\u00e0 un costo aggiuntivo, che non \u00e8 economico. A meno che tu non acceda a POJO molto pi\u00f9 frequentemente che alla stringa. In alternativa, si potrebbe cercare di decodificare la stringa ed estrarre solo quello che serve, senza convertirlo in POJO. Se tutto questo avviene in un contesto che richiede prestazioni massime, niente POJO: devi in qualche modo lavorare direttamente sulla stringa.<\/p>\n<p><\/p>\n<h1 id=\"zachem-sozdavat-svoy-yazyk-programmirovaniya\">Perch\u00e9 creare un proprio linguaggio di programmazione<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Hai detto che per comprendere il modello di costo, \u00e8 necessario scrivere un piccolo linguaggio\u2026<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Non un linguaggio, ma un compilatore. Linguaggio e compilatore sono due cose diverse. La differenza principale \u00e8 nella tua testa.\u00a0<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: A proposito, so che stai sperimentando la creazione di linguaggi propri. Perch\u00e9?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Perch\u00e9 posso! Sono in parte in pensione, quindi questo \u00e8 il mio hobby. Ho trascorso tutta la vita a realizzare lingue di qualcun altro. Inoltre, ho lavorato molto sullo stile di codifica. E anche perch\u00e9 vedo problemi in altre lingue. Vedo che ci sono modi migliori per fare cose familiari. E ne approfitterei. Sono semplicemente stanco di vedere problemi in me stesso, in Java, in Python, in qualsiasi altra lingua. Attualmente scrivo in React Native, JavaScript ed Elm come hobby, che non riguarda la pensione, ma un lavoro attivo. E scrivo anche in Python e probabilmente continuer\u00f2 a lavorare sull'apprendimento automatico per i backend Java. Ci sono molte lingue popolari e ognuna ha caratteristiche interessanti. Ognuna \u00e8 buona per qualcosa di proprio e si pu\u00f2 cercare di unire tutte queste caratteristiche. Quindi, sto studiando cose che mi interessano, il comportamento del linguaggio, cerco di inventare una semantica ragionevole. E finora ci riesco! Al momento sto lottando con la semantica della memoria, perch\u00e9 voglio averla come in C e Java, e ottenere un forte modello di memoria e semantica della memoria per i caricamenti e gli archiviazioni. Inoltre, avere un'inferenza automatica dei tipi come in Haskell. Sto cercando di mescolare l'inferenza dei tipi simile a Haskell con una memoria che funzioni come in C e Java. A questo mi dedico da 2-3 mesi, per esempio.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Se stai costruendo un linguaggio che prende i migliori aspetti da altre lingue, hai mai pensato che qualcuno potrebbe fare il contrario: prendere le tue idee e usarle per le proprie?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: \u00c8 proprio cos\u00ec che nascono nuovi linguaggi! Perch\u00e9 Java \u00e8 simile a C? Perch\u00e9 C aveva una buona sintassi, che tutti capivano, e Java \u00e8 stata ispirata da quella sintassi, aggiungendo sicurezza dei tipi, controllo dei limiti degli array, GC, e migliorando alcune cose di C. Hanno aggiunto anche le loro. Ma si sono ispirati piuttosto fortemente, giusto? Tutti stanno sulle spalle di giganti che sono venuti prima di te: \u00e8 cos\u00ec che avviene il progresso.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Da quanto ho capito, il tuo linguaggio sar\u00e0 sicuro per quanto riguarda l'uso della memoria. Hai pensato di implementare qualcosa come il borrow checker di Rust? Lo hai esaminato, cosa ne pensi?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Bene, scrivo in C da un'eternit\u00e0, con tutte queste malloc e free, e gestisco manualmente il ciclo di vita. Sapete, il 90-95% del ciclo di vita gestito manualmente ha una struttura simile. E \u00e8 davvero, davvero doloroso occuparsi di questo manualmente. Mi piacerebbe che il compilatore semplicemente dicesse cosa sta accadendo e cosa ho ottenuto con le mie azioni. Per alcune cose, il borrow checker lo fa automaticamente. E dovrebbe anche fornire informazioni in modo automatico, comprendere tutto e non caricarmi con il dover esprimere questa comprensione. Dovrebbe fare almeno un'analisi di escape locale, e solo se non ci riesce, allora bisogna aggiungere annotazioni sui tipi che descriveranno il ciclo di vita \u2013 e uno schema simile \u00e8 molto pi\u00f9 complesso del borrow checker, o di qualsiasi altro checker di memoria esistente. La scelta tra 'tutto a posto' e 'non ho capito nulla' \u2013 no, dovrebbe esserci qualcosa di migliore.\u00a0<br \/>\nQuindi, come persona che ha scritto molto codice in C, ritengo che avere supporto per la gestione automatica del lifetime sia una cosa estremamente importante. E sono anche stanco di quanto Java utilizzi memoria, con la principale lamentela riguardo al GC. Quando si allocca memoria in Java, non ti restituisce la memoria che era locale all'ultimo ciclo GC. Nei linguaggi con una gestione della memoria pi\u00f9 precisa, questo non accade. Se chiami malloc, ottieni immediatamente memoria che di solito \u00e8 stata appena utilizzata. Di solito fai delle operazioni temporanee con la memoria e la restituisci subito. E torna immediatamente nel pool di malloc, e il ciclo successivo di malloc la riutilizza di nuovo. Pertanto, il reale utilizzo della memoria si riduce a un insieme di oggetti vivi in un determinato momento, pi\u00f9 eventuali perdite. E se non hai perdite in modo del tutto inappropriato, la maggior parte della memoria si accumula nella cache e nel processore, e questo funziona rapidamente. Ma richiede una gestione manuale significativa della memoria tramite malloc e free, chiamati nel giusto ordine e nel posto giusto. Rust pu\u00f2 gestire tutto ci\u00f2 in modo corretto e, in molti casi, pu\u00f2 offrire anche migliori prestazioni, poich\u00e9 il consumo di memoria \u00e8 ridotto solo ai calcoli attuali, a differenza dell'attesa del successivo ciclo GC, che liberer\u00e0 memoria. Alla fine, abbiamo trovato un modo molto interessante per migliorare le prestazioni. E piuttosto potente - nel senso che mi sono occupato di argomenti simili nella gestione dei dati per il fintech, e questo portava a un incremento delle prestazioni di circa cinque volte. \u00c8 un aumento piuttosto significativo, specialmente in un mondo in cui i processori non diventano pi\u00f9 veloci e continuiamo a aspettare miglioramenti.<\/p>\n<p><\/p>\n<h1 id=\"karera-performans-inzhenera\">Carriera di ingegnere delle prestazioni<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Vorrei anche chiederti della carriera in generale. Sei diventato famoso grazie al lavoro sul JIT in HotSpot, poi sei passato ad Azul, che \u00e8 anch'essa un'azienda JVM. Ma ti sei occupato di pi\u00f9 di hardware che di software. E poi all'improvviso ti sei concentrato su Big Data e Machine Learning, per poi passare alla rilevazione delle frodi. Come ci sei arrivato? Sono aree di sviluppo molto diverse.<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Ho iniziato a programmare ormai da molto tempo e ho avuto esperienze in attivit\u00e0 molto diverse. E quando la gente dice: \u00abOh, sei tu quello che ha fatto il JIT per Java!\u00bb, \u00e8 sempre divertente. Eppure prima di questo mi occupavo di un clone di PostScript, quel linguaggio che Apple una volta usava per le sue stampanti laser. E prima ancora avevo realizzato un'implementazione del linguaggio Forth. Penso che il tema centrale per me sia lo sviluppo di strumenti. Per tutta la vita ho creato strumenti, attraverso i quali altre persone scrivono i loro programmi incredibili. Ma mi sono anche occupato dello sviluppo di sistemi operativi, driver, debugger a livello di kernel, linguaggi per lo sviluppo di sistemi operativi, che iniziavano in modo triviale, ma che nel tempo diventavano sempre pi\u00f9 complessi. Tuttavia, il tema principale rimane comunque lo sviluppo di strumenti. Una grande parte della mia vita \u00e8 passata tra Azul e Sun, ed \u00e8 stata dedicata a Java. Ma quando mi sono occupato di Big Data e Machine Learning, ho indossato di nuovo il mio cappello da cerimonia e ho detto: \u00abOh, ora abbiamo un problema non banale, e qui stanno succedendo molte cose interessanti e ci sono persone che stanno facendo qualcosa\u00bb. Questo \u00e8 un ottimo percorso di sviluppo da seguire. <\/p>\n<p><\/p>\n<p>S\u00ec, mi piacciono molto i calcoli distribuiti. Il mio primo lavoro \u00e8 stato all'universit\u00e0 in C, su un progetto pubblicitario. Si trattava di calcoli distribuiti su chip Zilog Z80, che raccoglievano dati per il riconoscimento testuale ottico analogico, effettuato da un vero analizzatore analogico. Era un tema interessante e completamente fuori dal comune. Ma c'erano problemi, una parte non veniva riconosciuta correttamente, quindi dovevamo estrarre l'immagine e mostrarla a una persona che l'aveva gi\u00e0 letta a occhio e comunicava cosa si diceva, e per questo c'erano lavori con dati, e questi lavori avevano il loro linguaggio. C'era un backend che gestiva tutto questo: Z80 in esecuzione in parallelo con terminali vt100 attivi \u2013 uno per persona, e c'era un modello di programmazione parallela su Z80. Un certo pezzo di memoria condivisa che veniva condiviso da tutti gli Z80 all'interno di una configurazione a stella; veniva condiviso anche il backplane, met\u00e0 della RAM era condivisa all'interno della rete, e l'altra met\u00e0 era privata o utilizzata per qualcos'altro. Un sistema distribuito parallelo semplificato con memoria condivisa... semi-condivisa. Quando \u00e8 stato... Gi\u00e0 non ricordo, da qualche parte a met\u00e0 degli anni '80. Davvero tanto tempo fa.\u00a0<br \/>\nS\u00ec, direi che 30 anni \u00e8 abbastanza tempo. I compiti legati ai calcoli distribuiti esistono da molto tempo, le persone da tempo combattono con <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/Beowulf_(%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80)\">Beowulf<\/a><\/noindex>-cluster. Tali cluster sembrano come\u2026 Per esempio: c'\u00e8 Ethernet e il tuo veloce x86 \u00e8 collegato a questo Ethernet, e ora vuoi ottenere una fake shared memory, perch\u00e9 nessuno poteva allora dedicarsi alla codifica di calcoli distribuiti, era troppo complicato e quindi c'era una fake shared memory con protezione delle pagine di memoria su x86, e se scrivevi in questa pagina, dicevamo agli altri processori che se avessero avuto accesso alla stessa shared memory, dovevano scaricarla da te. In questo modo, \u00e8 emerso qualcosa di simile a un protocollo di supporto alla coerenza della cache e software per questo. Concetto interessante. Il vero problema, ovviamente, era altro. Tutto ci\u00f2 funzionava, ma rapidamente ti trovavi a dover affrontare problemi di prestazioni, poich\u00e9 nessuno comprendeva il modello di prestazioni a un livello sufficientemente buono: quali fossero i pattern di accesso alla memoria, come fare in modo che i nodi non si pingassero continuamente l'un l'altro, e cos\u00ec via. <\/p>\n<p><\/p>\n<p>In H2O ho concepito quanto segue: gli sviluppatori stessi sono responsabili di identificare dove si nasconde il parallelismo e dove non c'\u00e8. Ho ideato un modello di codifica che rende facile e semplice scrivere codice ad alte prestazioni. Invece, scrivere codice lento \u00e8 difficile, risulter\u00e0 sgradevole. \u00c8 necessario impegnarsi seriamente per scrivere codice lento, occorrer\u00e0 utilizzare metodi non standard. Il codice che rallenta \u00e8 evidente a prima vista. Di conseguenza, di solito si scrive codice che funziona velocemente, ma ci si deve chiedere che fare nel caso di memoria condivisa. Tutto ci\u00f2 \u00e8 legato a grandi array e il comportamento l\u00ec \u00e8 simile a grandi array non volatili in parallelo in Java. Cio\u00e8, immaginate che due thread scrivano in un array parallelo, uno di essi vince, mentre l'altro, di conseguenza, perde, e non sapete quale sia quale. Se non sono volatili, l'ordine pu\u00f2 essere qualsiasi \u2013 e funziona davvero bene. Le persone si preoccupano dell'ordine delle operazioni, posizionano correttamente volatile e nei luoghi giusti si aspettano problemi di prestazioni legati alla memoria. Altrimenti scriverebbero semplicemente codice sotto forma di cicli da 1 a N, dove N \u00e8 qualche trilione, sperando che tutti i casi complessi diventino automaticamente paralleli \u2013 e l\u00ec non funziona. Ma in H2O non \u00e8 Java e non \u00e8 neppure Scala, si potrebbe considerare come \"Java meno meno\", se si vuole. \u00c8 uno stile di programmazione molto chiaro e sembra scrivere codice semplice in C o Java con cicli e array. Ma da questo punto di vista, la memoria pu\u00f2 essere gestita in terabyte. Uso ancora H2O. Di tanto in tanto lo uso in vari progetti \u2013 ed \u00e8 ancora la cosa pi\u00f9 veloce, di decine di volte superiore ai concorrenti. Se stai lavorando con Big Data su dati a colonne, \u00e8 molto difficile superare H2O.<\/p>\n<p><\/p>\n<h1 id=\"tehnicheskie-chellenzhi\">Sfide tecniche<\/h1>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Qual \u00e8 stata la sfida pi\u00f9 grande della tua carriera?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Stiamo discutendo della parte tecnica o di quella non tecnica della questione? Direi che le sfide pi\u00f9 grandi non sono tecniche.\u00a0<br \/>\nPer quanto riguarda le sfide tecniche, le ho semplicemente superate. Non so nemmeno quale sia stata la pi\u00f9 grande, ma ci sono state diverse sfide piuttosto interessanti che hanno richiesto molto tempo e impegno mentale. Quando sono andato in Sun, ero sicuro di poter creare un compilatore veloce, ma molti senior mi dicevano che non sarei mai riuscito a farlo. Ma ho continuato su questa strada, ho scritto un compilatore fino all'allocatore di registri, ed \u00e8 stato piuttosto veloce. Era tanto veloce quanto il moderno C1, ma all'epoca l'allocatore era molto pi\u00f9 lento, e guardando indietro, questo era un problema della grande struttura dati. Avevo bisogno di essa per scrivere un allocatore di registri grafico e non capivo il dilemma tra l'espressivit\u00e0 del codice e la velocit\u00e0, che esisteva in quell'epoca ed era molto importante. Si \u00e8 rivelato che la struttura dati di solito superava le dimensioni della cache sugli x86 dell'epoca e quindi, se inizialmente pensavo che l'allocatore di registri avrebbe occupato il 5-10% del tempo totale di JIT, in realt\u00e0 si \u00e8 tradotto in un 50%. <\/p>\n<p><\/p>\n<p>Il tempo passava, il compilatore diventava sempre pi\u00f9 chiaro e performante, smetteva di generare codice orrido in un numero maggiore di casi, e le prestazioni cominciavano a somigliare a quelle di un compilatore C. Se, ovviamente, non scrivi qualcosa di brutto che nemmeno il C riesce ad accelerare. Se scrivi codice come in C, ottieni prestazioni simili a quelle del C in un numero maggiore di casi. E man mano che andavamo avanti, il codice cominciava ad coincidere asintoticamente con il livello C, l'allocatore di registri cominci\u00f2 a somigliare a qualcosa di finale... a prescindere che il tuo codice funzionasse velocemente o lentamente. Continuai a lavorare sull'allocatore, affinch\u00e9 producesse assegnazioni migliori. Diventava sempre pi\u00f9 lento, ma offriva prestazioni sempre migliori nei casi in cui nessun altro riusciva. Potevo immergermi nell'allocatore di registri, spendere un mese di lavoro, e all'improvviso tutto il codice cominciava a girare il 5% pi\u00f9 velocemente. Questo accadeva ripetutamente e l'allocatore di registri divenne una sorta di opera d'arte \u2013 tutti lo amavano o lo odiavano, e le persone dell'accademia facevano domande su \"perch\u00e9 tutto fosse fatto proprio in quel modo\", perch\u00e9 non <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Register_allocation#Linear_Scan\">scansione lineare<\/a><\/noindex>, e qual \u00e8 la differenza. La risposta \u00e8 sempre la stessa: un allocatore basato sulla colorazione del grafo pi\u00f9 un lavoro molto accurato con il codice del buffer \u00e8 uguale a uno strumento di vittoria, la migliore combinazione che nessuno pu\u00f2 superare. E questa \u00e8 una cosa abbastanza non ovvia. Tutto il resto che fa il compilatore sono cose piuttosto consolidate, anche se anch'esse portate a un livello artistico. Ho sempre fatto cose che avrebbero dovuto trasformare il compilatore in un'opera d'arte. Ma nulla di tutto ci\u00f2 era straordinario \u2013 tranne l'allocatore di registri. Il punto \u00e8 che bisogna lavorare con cautela <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Register_allocation\">tagliare<\/a><\/noindex> sotto carico e, se ci\u00f2 avviene (posso spiegare in dettaglio se \u00e8 interessante), significa che si pu\u00f2 effettuare l'inlining in modo pi\u00f9 aggressivo, senza il rischio di oltrepassare il punto di rottura della prestazione. All'epoca c'erano un sacco di compilatori completi, zeppi di gadget e fronzoli, che avevano allocatori di registri, ma nessuno riusc\u00ec mai a farlo di nuovo. <\/p>\n<p><\/p>\n<p>Il problema \u00e8 che, se aggiungi metodi soggetti a inlining, aumentando sempre di pi\u00f9 l'area di inlining, il set di valori utilizzati supera istantaneamente il numero di registri, e sei costretto a spillare. Il livello critico di solito si verifica quando l'allocatore cede, e un buon candidato per lo spillage vale l'altro; inizi a spillare cose davvero strane. Il valore dell'inlining qui \u00e8 che perdi parte dell'overhead, l'overhead della chiamata e del salvataggio, puoi vedere i valori all'interno e puoi ottimizzarli ulteriormente. Il costo dell'inlining \u00e8 che si genera un gran numero di valori vivi, e se il tuo allocatore di registri spillera pi\u00f9 di quanto necessario, perdi immediatamente. Per questo motivo, la maggior parte degli allocatori ha un problema: quando l'inlining oltrepassa una certa soglia, inizia a spillare tutto ed \u00e8 possibile che le prestazioni vengano spazzate via. Coloro che implementano il compilatore aggiungono alcune euristiche: ad esempio, per fermare l'inlining, partendo da una dimensione sufficientemente grande, poich\u00e9 le allocazioni rovineranno tutto. Cos\u00ec si crea una frattura nel grafico delle prestazioni \u2013 fai inlining, fai inlining, le prestazioni crescono lentamente \u2013 e poi bam! \u2013 crolla a picco, perch\u00e9 hai inlinato troppo. Cos\u00ec \u00e8 andata fino all'arrivo di Java. Java richiede molto pi\u00f9 inlining, quindi ho dovuto rendere il mio allocatore molto pi\u00f9 aggressivo, affinch\u00e9 si stabilizzasse e non crollasse, e se hai inlinato troppo \u2013 inizia a spillare, ma poi c'\u00e8 comunque un momento in cui<\/p>\n<p><\/p>\n<h1 id=\"nemnogo-pro-allokaciyu-registrov-i-mnogoyadernost\">Qualche nota sull'allocazione dei registri e sulla multithreading<\/h1>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Problemi come l'allocazione dei registri sembrano essere un tema infinito e senza fine. \u00c8 interessante sapere se ci sia stata un'idea che sembrava promettente e poi \u00e8 fallita nella pratica?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Certo! L'allocazione dei registri \u00e8 un'area in cui, per risolvere un problema NP-completo, cerchi di trovare delle euristiche. E non riuscirai mai a trovare una soluzione perfetta, giusto? \u00c8 semplicemente impossibile. Vedi, la compilazione Ahead of Time funziona male anch'essa. Qui si parla di casi medi. Della prestazione tipica, quindi puoi andare a misurare qualcosa che consideri una buona prestazione tipica \u2013 dopotutto, stai lavorando per migliorarlo! L'allocazione dei registri \u00e8 un argomento interamente dedicato alla prestazione. Una volta che hai il primo prototipo, che funziona e fa quello che deve, inizia il lavoro sulla prestazione. Devi imparare a misurare bene. Perch\u00e9 \u00e8 importante? Se hai dati chiari, puoi guardare in diverse aree e vedere: ah, questo ha aiutato qui, ma l\u00e0 \u00e8 tutto andato male! Nascono delle buone idee, aggiungi una nuova euristica e all'improvviso tutto inizia a funzionare leggermente meglio in media. O magari non inizia. Ho avuto un sacco di casi in cui abbiamo combattuto per cinque percento di prestazione, che distingueva il nostro sviluppo dal precedente allocatore. E ogni volta si presentava cos\u00ec: hai vinto in un punto, hai perso in un altro. Se hai buoni strumenti di analisi delle prestazioni, puoi identificare le idee perdenti e capire perch\u00e9 stanno perdendo. Forse vale la pena mantenere tutto com'\u00e8, oppure affrontare seriamente il tuning fine, o andare a sistemare qualcos'altro. \u00c8 un intero insieme di cose! Ho realizzato questo fantastico hack, ma serve anche questo, e questo, e quest'altro \u2013 e la loro combinazione complessiva porta a dei miglioramenti. E le soluzioni singole possono fallire. Questa \u00e8 la natura del lavoro su problemi NP-completi.<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Sembra che cose come la verniciatura negli allocatori siano una questione gi\u00e0 risolta. Beh, per voi sembra risolta, a giudicare da quello che raccontate, quindi vale comunque la pena\u2026<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Non \u00e8 risolta in quanto tale. Devi trasformarla in \"risolta\". Ci sono problemi difficili e devono essere affrontati. Una volta che ci\u00f2 \u00e8 fatto, arriva il momento di lavorare sulle prestazioni. Questa attivit\u00e0 deve essere presa sul serio: fare benchmark, raccogliere metriche, spiegare situazioni in cui, tornando a una versione precedente, il tuo vecchio hack ha ricominciato a funzionare (o viceversa, ha smesso di funzionare). E non retrocedere finch\u00e9 non ottieni qualcosa. Come ho gi\u00e0 detto, se ci sono idee geniali che non hanno funzionato, nel campo dell'allocazione dei registri, le idee sono praticamente infinite. Ad esempio, puoi leggere pubblicazioni scientifiche. Anche se ora questo campo si sta muovendo molto pi\u00f9 lentamente ed \u00e8 diventato pi\u00f9 chiaro rispetto ai suoi tempi di giovent\u00f9. Tuttavia, in questo campo lavora un'infinit\u00e0 di persone e tutte le loro idee meritano di essere provate, tutte aspettano il loro momento. E non puoi dire quanto siano buone se non provi. Quanto bene si integrano con tutto il resto nel tuo allocatore, visto che l'allocatore fa molte cose, e alcune idee nel tuo specifico allocatore potrebbero non funzionare, mentre in un altro allocatore funzionerebbero benissimo. Il modo principale per vincere per un allocatore \u00e8 rimuovere le parti lente dal percorso principale e forzare la divisione lungo i confini dei percorsi lenti. Quindi, se vuoi avviare la GC, seguire il percorso lento, deottimizzarti, generare un'eccezione, tutto in quel modo \u2013 sai che questi eventi sono relativamente rari. E lo sono davvero, ho verificato. Fai lavoro extra e grazie a questo svaniscono molte limitazioni su quei percorsi lenti, ma non \u00e8 molto importante perch\u00e9 sono lenti e raramente usati. Ad esempio, il puntatore nullo \u2013 non si verifica mai, giusto? Devi avere diversi percorsi per diverse cose, ma non devono interferire tra loro nel principale.\u00a0<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Cosa pensate della multicoresenza quando ci sono migliaia di core? \u00c8 una cosa utile?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Il successo delle GPU dimostra che \u00e8 piuttosto utile!<\/p>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: Sono abbastanza specializzati. E per quanto riguarda i processori a uso generale?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: Bene, questo era il modello di business di Azul. La risposta \u00e8 arrivata ancora nell'era in cui le persone amavano molto le prestazioni prevedibili. All'epoca era difficile scrivere codice parallelo. Il modello di codifica H2O si scala bene, ma non \u00e8 un modello di uso generale. A meno che non sia leggermente pi\u00f9 generale rispetto all'uso della GPU. Parliamo della complessit\u00e0 nello sviluppo di una cosa del genere o della complessit\u00e0 del suo utilizzo? Ad esempio, Una lezione interessante che mi ha insegnato Azul, piuttosto poco ovvia: le piccole cache vanno bene.\u00a0<\/p>\n<p><\/p>\n<h1 id=\"samyy-bolshoy-chellenzh-v-zhizni\">La sfida pi\u00f9 grande della vita<\/h1>\n<p><\/p>\n<p><strong>Vladimir<\/strong>: E per quanto riguarda le sfide non tecniche?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: La sfida pi\u00f9 grande \u00e8 stata non essere... gentile e buono con le persone. Di conseguenza, mi sono costantemente trovato in situazioni estremamente conflittuali. Situazioni in cui sapevo che tutto stava andando storto, ma non sapevo come andare avanti nella soluzione di questi problemi e non sono riuscito a gestirli. Molti problemi di lunga durata, che durano da decenni, sono emersi in questo modo. Il fatto che in Java esistano i compilatori C1 e C2 \u00e8 una diretta conseguenza di questo. Il fatto che in Java per dieci anni non ci sia stata la compilazione multilivello \u00e8 anch'esso una diretta conseguenza. \u00c8 ovvio che avevamo bisogno di un sistema del genere, ma non \u00e8 ovvio perch\u00e9 non ci fosse. Ho avuto problemi con un ingegnere... o un gruppo di ingegneri. Tanto tempo fa, quando ho iniziato a lavorare in Sun, ero... Va bene, non solo allora, ho sempre un'opinione su tutto. E credevo fosse vero che potessi semplicemente prendere questa mia verit\u00e0 e dirla in faccia. Soprattutto, dato che avevo ragione in modo scioccante la maggior parte del tempo. E se a qualcuno questo approccio non piace... specialmente se \u00e8 chiaramente in errore e sta combinando guai... In generale, poche persone potevano tollerare tale forma di comunicazione. Anche se alcuni lo potevano, per esempio, io. Ho basato tutta la mia vita su principi meritocratici. Se mi mostri qualcosa di sbagliato, giro i tacchi e dico: hai detto una sciocchezza. Naturalmente, mi scuso e tutto il resto, riconosco i meriti, se ci sono, e compio altre azioni corrette. D'altra parte, ho ragione in modo scioccante una percentuale sorprendentemente alta del tempo. E questo non funziona molto bene nelle relazioni con le persone. Non mi sforzo di essere gentile, ma metto il problema sul tavolo. \"Questo non funzioner\u00e0 mai, perch\u00e9 una, due e tre\". E loro: \"Oh!\". Ci sono stati anche altri effetti, che \u00e8 meglio probabilmente saltare: per esempio, quelli che hanno portato al divorzio da mia moglie e a un decennio di depressione dopo.<\/p>\n<p><\/p>\n<p>La sfida \u00e8 una lotta con le persone, con la loro percezione di ci\u00f2 che puoi o non puoi fare, cosa \u00e8 importante e cosa no. Ci sono state molte sfide riguardo allo stile di codifica. Continuo a scrivere molto codice e in quei tempi dovetti addirittura rallentare perch\u00e9 facevo troppe attivit\u00e0 parallele e le facevo male, invece di concentrarmi su una sola. Ripensando, ho scritto met\u00e0 del codice del team Java JIT, del team C2. Il prossimo programmatore pi\u00f9 veloce scriveva la met\u00e0 pi\u00f9 lentamente, il successivo era ancora pi\u00f9 lento ed \u00e8 stata una caduta esponenziale. Il settimo in questa fila era molto, molto lento - \u00e8 cos\u00ec che va sempre! Ho toccato un sacco di codice. Ho osservato chi scrive cosa, senza eccezioni, ho fissato il loro codice, ho riveduto ognuno di loro e continuavo a scrivere pi\u00f9 di qualsiasi di loro. Con le persone, questo approccio non funziona molto bene. Alcuni non lo apprezzano. E quando non riescono a gestirlo, iniziano le lamentele di ogni genere. Per esempio, una volta mi \u00e8 stato detto di smettere di scrivere codice perch\u00e9 ne scrivo troppo e questo mette in pericolo il team, e tutto questo mi \u00e8 sembrato una battuta: amico, se tutto il resto del team sparisse e io continuassi a scrivere codice, perderesti solo met\u00e0 del team. D'altra parte, se continuo a scrivere codice e tu perdi met\u00e0 del team - questo suona come unvery bad management. Non ci ho mai riflettuto troppo, non ne ho mai parlato, ma in qualche modo era sempre nella mia testa. Nelle retrovie della mia coscienza continuava a girare il pensiero: 'Ma state scherzando?'. Quindi, il problema pi\u00f9 grande ero io e le mie relazioni con le persone. Ora mi capisco molto meglio, ho fatto da team leader con i programmatori e ora parlo direttamente alla gente: sai, io sono quello che sono e dovrete fare i conti con me - va bene se rimango qui? E quando hanno iniziato a gestirlo, tutto ha funzionato. Non sono realmente n\u00e9 cattivo n\u00e9 buono, non ho cattive intenzioni o obiettivi egoistici, \u00e8 semplicemente la mia essenza e bisogna convivere con essa.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: Recentemente si \u00e8 parlato moltissimo di autoconsapevolezza per gli introversi, e in generale delle soft skills. Cosa si pu\u00f2 dire al riguardo?<\/p>\n<p><\/p>\n<p><strong>Cliff<\/strong>: S\u00ec, \u00e8 stata una comprensione e una lezione che ho appreso dal mio divorzio con mia moglie. Ci\u00f2 che ho tratto dal divorzio \u00e8 stata la comprensione di me stesso. Cos\u00ec ho iniziato a comprendere le altre persone. Comprendere come funziona questa interazione. Ha portato a scoperte una dopo l'altra. \u00c8 emersa la consapevolezza di chi sono e cosa rappresento. Cosa faccio: o sono preoccupato per il compito, o evito il conflitto, o qualcos'altro \u2013 e tale livello di autoconsapevolezza aiuta davvero a mantenere il controllo. Dopo ci\u00f2, tutto procede molto pi\u00f9 facilmente. Una cosa che ho scoperto non solo in me stesso, ma anche in altri programmatori, \u00e8 l'impossibilit\u00e0 di verbalizzare i pensieri quando ci si trova in uno stato di stress emotivo. Ad esempio, sei l\u00ec a scrivere codice, sei in uno stato di flusso, e poi qualcuno corre da te e inizia a urlare in preda alla disperazione che qualcosa \u00e8 andato storto e verranno adottate misure drastiche. E non riesci nemmeno a dire una parola perch\u00e9 sei in uno stato di stress emotivo. Le conoscenze acquisite consentono di prepararsi a quel momento, di viverlo e di passare a un piano di ritirata, dopo il quale si pu\u00f2 gi\u00e0 fare qualcosa. Quindi s\u00ec, quando inizi a renderti conto di come funziona tutto questo \u2013 \u00e8 un evento enorme che cambia la vita.\u00a0<br \/>\nIo stesso non sono riuscito a trovare le parole giuste, ma ho ricordato la sequenza di azioni. Il punto \u00e8 che questa reazione \u00e8 tanto fisica quanto verbale, e hai bisogno di spazio. Uno spazio di questo tipo, in un senso zen. \u00c8 proprio questo che bisogna spiegare, e poi subito allontanarsi \u2013 fisicamente allontanarsi. Quando tacito a parole, posso elaborare la situazione in termini di emozioni. Man mano che l'adrenalina raggiunge il cervello, ti mette in modalit\u00e0 'combatti o fuggi', non riesci pi\u00f9 a dire nulla, no \u2013 ora sei un idiota, un ingegnere da colpire, incapace di dare una risposta dignitosa o di almeno fermare l'attacco, e l'aggressore pu\u00f2 attaccare liberamente ancora e ancora. Prima di tutto, \u00e8 necessario tornare a essere se stessi, riprendere il controllo, uscire dalla modalit\u00e0 'combatti o fuggi'. <\/p>\n<p><\/p>\n<p>Ecco perch\u00e9 \u00e8 necessario uno spazio verbale. Uno spazio libero. Se si deve parlare, si pu\u00f2 dichiarare questo e poi andare a cercare realmente il proprio \u00abspazio\u00bb: fare una passeggiata nel parco, chiudersi in doccia \u2013 non importa. La cosa importante \u00e8 disconnettersi temporaneamente dalla situazione. Non appena riesci a disconnetterti anche solo per qualche secondo, il controllo torna, inizi a pensare in modo lucido. \u00abBene, non sono un idiota, non faccio cose stupide, sono una persona piuttosto utile\u00bb. Non appena sei riuscito a convincere te stesso, \u00e8 tempo di passare alla fase successiva: capire cosa sia successo. Sei stato attaccato, l'attacco \u00e8 venuto da dove non te lo aspettavi, \u00e8 stata un'imboscata sleale e subdola. \u00c8 male. Il passo successivo \u00e8 capire perch\u00e9 l'attaccante avesse bisogno di farlo. Davvero, perch\u00e9? Forse perch\u00e9 \u00e8 lui stesso in preda alla rabbia? Perch\u00e9 \u00e8 in preda alla rabbia? Ad esempio, perch\u00e9 ha fallito e non riesce ad assumersi la responsabilit\u00e0? In questo modo bisogna elaborare la situazione con attenzione. Ma per questo serve uno spazio di manovra, uno spazio verbale. Il primo passo \u00e8 rompere il contatto verbale. Allontanarsi dalla discussione a parole. Cancellalo, allontanati il prima possibile. Se si tratta di una conversazione telefonica, riattacca semplicemente \u2013 \u00e8 un'abilit\u00e0 che ho acquisito dalla mia comunicazione con l'ex moglie. Se la conversazione non porta a nulla di buono, d\u00ec semplicemente \u00abarrivederci\u00bb e riattacca. Dall'altra parte del telefono: \u00abbla-bla-bla\u00bb, tu rispondi: \u00abah, ciao!\u00bb e riattacchi. Rompi semplicemente la conversazione. Cinque minuti dopo, quando torna a te la capacit\u00e0 di pensare in modo lucido, ti sei un po' raffreddato, diventa possibile riflettere su cosa sia realmente successo e su cosa accadr\u00e0 dopo. E inizia a formulare una risposta ragionata, piuttosto che reagire semplicemente sulle emozioni. Per me, una svolta nella consapevolezza di s\u00e9 \u00e8 stata proprio quella che, in caso di stress emotivo, non riesco a parlare. Uscire da questo stato, riflettere e pianificare come rispondere e compensare i problemi \u2013 sono questi i passi giusti quando non puoi parlare. Il modo pi\u00f9 semplice \u00e8 scappare dalla situazione in cui si manifesta lo stress emotivo e semplicemente smettere di partecipare a questo stress. Dopo di che, riconquisti la capacit\u00e0 di pensare, quando puoi pensare, si presenta l'opportunit\u00e0 di parlare e cos\u00ec via.<\/p>\n<p><\/p>\n<p>A proposito, in tribunale l'avvocato della parte avversa cerca di fare questo con te - ora \u00e8 chiaro perch\u00e9. Perch\u00e9 ha la possibilit\u00e0 di schiacciarti fino a un tale stato che non potrai nemmeno pronunciare il tuo nome, per esempio. Nel senso pi\u00f9 diretto, non potrai parlare. Se ti capita di vivere questo e sai che ti troverai in un luogo dove ci sono battaglie verbali, in un luogo come il tribunale, puoi arrivare con il tuo legale. L'avvocato ti difender\u00e0 e fermer\u00e0 l'attacco verbale, e lo far\u00e0 in modo del tutto legale, e ti restituir\u00e0 lo spazio zen perduto. Per esempio, ho dovuto chiamare la mia famiglia un paio di volte, il giudice \u00e8 stato abbastanza cordiale, ma l'avvocato della parte avversa urlava e urlava contro di me, non riuscivo nemmeno a inserire una parola. In questi casi, per me funziona meglio utilizzare un mediatore. Il mediatore ferma tutta questa pressione che ti travolge in un flusso incessante, scopri lo spazio zen necessario, insieme ad esso ritorna la capacit\u00e0 di parlare. \u00c8 un intero campo di conoscenze, in cui \u00e8 necessario studiare molto, scoprire molte cose dentro di s\u00e9, e tutto questo si trasforma in soluzioni strategiche di alto livello, diverse per persone diverse. Alcuni non hanno problemi descritti sopra, di solito, non li hanno le persone che lavorano professionalmente nelle vendite. Tutte queste persone che guadagnano da vivere con le parole - cantanti, poeti, leader religiosi e politici noti, loro hanno sempre qualcosa da dire. Non hanno questi problemi, mentre io s\u00ec.<\/p>\n<p><\/p>\n<p><strong>Andrey<\/strong>: \u00c8 stato... inaspettato. Ottimo, abbiamo gi\u00e0 parlato molto e ora \u00e8 tempo di concludere questa intervista. Ci incontreremo sicuramente alla conferenza e potremo continuare questo dialogo. Ci vediamo su Hydra!<\/p>\n<p><\/p>\n<blockquote><p>Continua la comunicazione con Cliff alla conferenza Hydra 2019, che si terr\u00e0 l'11-12 luglio 2019 a San Pietroburgo. Arriver\u00e0 con una presentazione <noindex><a rel=\"nofollow\" href=\"https:\/\/hydraconf.com\/2019\/talks\/2jix5mst7iduyp9linqhfj\/?utm_source=habr&amp;utm_medium=45871\">\u00abL'esperienza della memoria transazionale hardware Azul\u00bb<\/a><\/noindex>. I biglietti possono essere acquistati <noindex><a rel=\"nofollow\" href=\"https:\/\/hydraconf.ru\/?utm_source=habr&amp;utm_medium=458718\">sul sito ufficiale<\/a><\/noindex>.<\/p><\/blockquote>\n<p>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/jugru\/blog\/458718\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014 CTO \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 Cratus (IoT \u0441\u0435\u043d\u0441\u043e\u0440\u044b \u0434\u043b\u044f \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432), \u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438 \u0441\u043e\u043e\u0441\u043d\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0441\u0442\u0430\u0440\u0442\u0430\u043f\u043e\u0432 (\u0432\u043a\u043b\u044e\u0447\u0430\u044f Rocket Realtime School, Neurensic \u0438 H2O.ai) \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0443\u0441\u043f\u0435\u0448\u043d\u044b\u043c\u0438 \u044d\u043a\u0437\u0438\u0442\u0430\u043c\u0438. \u041a\u043b\u0438\u0444\u0444 \u043d\u0430\u043f\u0438\u0441\u0430\u043b \u0441\u0432\u043e\u0439 \u043f\u0435\u0440\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u0432 15 \u043b\u0435\u0442 (Pascal \u0434\u043b\u044f TRS Z-80)! \u041d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d \u0437\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u043d\u0430\u0434 \u04212 \u0432 Java (the Sea of Nodes IR). \u042d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u043f\u043e\u043a\u0430\u0437\u0430\u043b [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-35851","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e \u0441 \u041a\u043b\u0438\u0444\u0444\u043e\u043c \u041a\u043b\u0438\u043a\u043e\u043c \u2014 \u043e\u0442\u0446\u043e\u043c JIT-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0432 Java | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:07:03+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:07:03+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Grande intervista con Cliff Click \u2014 il padre della compilazione JIT in Java | ProHoster","description":"Cliff Click \u2014.","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0411\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u044c\u044e \u0441 \u041a\u043b\u0438\u0444\u0444\u043e\u043c \u041a\u043b\u0438\u043a\u043e\u043c \u2014 \u043e\u0442\u0446\u043e\u043c JIT-\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0446\u0438\u0438 \u0432 Java | ProHoster","og:description":"\u041a\u043b\u0438\u0444\u0444 \u041a\u043b\u0438\u043a \u2014.","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/bolshoe-intervyu-s-kliffom-klikom-ottsom-jit-kompilyatsii-v-java","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:07:03+00:00","article:modified_time":"2019-10-31T19:07:03+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"35851","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-22 01:01:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:55:25","updated":"2026-01-22 01:01:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35851","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=35851"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/35851\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=35851"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=35851"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=35851"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}