.NET è una piattaforma di sviluppo software creata da Microsoft, pensata per costruire applicazioni moderne e performanti su diversi ambienti, tra cui Windows, macOS, Linux, dispositivi mobili e il Web. Offre un insieme completo di strumenti, librerie e runtime che semplificano la scrittura, il debug e l’esecuzione di software in linguaggi come C#, F# e Visual Basic. Grazie alla sua architettura modulare e alla compatibilità cross-platform, .NET consente agli sviluppatori di creare applicazioni scalabili, sicure e facilmente manutenibili, dall’enterprise software ai servizi cloud. Le moderne versioni di .NET sono molto differenti rispetto agli storici Framework .NET.
Il rilascio di .NET 10 come versione LTS (Long-Term Support), con supporto esteso a ben 3 anni, rappresenta un momento di fondamentale importanza per sviluppatori e aziende che utilizzano la piattaforma, offrendo stabilità, affidabilità e un ambiente solido.
Con il rilascio di .NET 10, Microsoft introduce una serie di ottimizzazioni mirate che migliorano sensibilmente le prestazioni delle applicazioni. Frutto di centinaia di interventi incrementali rispetto alle versioni precedenti, rappresentano un significativo passo avanti nel modo in cui il runtime gestisce la compilazione Just-In-Time (JIT), la gestione della memoria e l’esecuzione del codice.
L’effetto cumulativo delle micro-ottimizzazioni in .NET 10
In una lunga e tecnica presentazione, Stephen Toub (Microsoft Partner Software Engineer) fa un paragone con innovazioni storiche come la conservazione del ghiaccio di Frederic Tudor nel XIX secolo. .NET 10, infatti, non punta a una singola rivoluzione, ma a centinaia di micro-ottimizzazioni.
Ogni nanosecondo risparmiato e ogni byte non allocato contribuiscono a un aumento significativo delle performance in scenari reali, dove miliardi di operazioni sono eseguite ogni secondo.
Toub descrive esempi e risultati di benchmark lanciati con BenchmarkDotNet su Ubuntu 24.04.1 LTS, avvalendosi di un chip x64 Intel Core i9 di undicesima generazione. I test effettuati mettono a confronto l’esecuzione delle applicazioni tra .NET 9 e .NET 10, offrendo dati quantitativi sulle differenti ottimizzazioni introdotte.
Ottimizzazioni JIT: volano per velocizzare le app .NET 10
Uno dei principali colli di bottiglia storici di .NET si chiama “abstraction penalty”: è il costo aggiuntivo introdotto dall’uso di astrazioni come interfacce, iteratori e delegati. Queste, infatti, rendono il codice più chiaro, modulare e flessibile, ma introducono passaggi extra (allocazioni, lookup dinamici, gestione di oggetti temporanei) che aumentano il tempo di esecuzione e il consumo di memoria.
.NET 10 estende l’utilizzo della cosiddetta escape analysis, permettendo l’allocazione di oggetti nello stack quando questi non fuoriescono dal metodo. Si chiama escape analysis la tecnica utilizzata dal JIT per determinare se un oggetto rimane confinato all’interno di un singolo metodo o se invece è “trasferito” al di fuori (ad esempio restituendolo come valore di ritorno o assegnandolo a una classe).
Un delegato in C# è un oggetto che “punta” a un metodo da eseguire. Con .NET 10, JIT riesce a rilevare quando un delegato non utilizza il riferimento all’oggetto (this
) e viene usato solo all’interno del metodo. In questi casi, proprio grazie alla escape analysis, il delegato può essere creato direttamente nello stack del metodo, cioè nella memoria temporanea già usata dal metodo stesso. Stesso approccio è applicato per la gestione degli array locali temporanei. Il risultato è che la latenza delle chiamate risulta ridotta e diminuisce il consumo di memoria complessivo.
Come il runtime diventa ancora più veloce e leggero
In .NET, alcune funzionalità come metodi virtuali, interfacce e array rendono il codice flessibile, ma introducono piccoli rallentamenti. Questo perché il runtime deve decidere quale metodo concreto andare a chiamare mentre l’applicazione è in esecuzione: il processo è chiamato dispatch dinamico.
Con .NET 10, il runtime riesce a trasformare molte chiamate virtuali in chiamate dirette, eliminando il passaggio aggiuntivo necessario per capire quale metodo eseguire. Il risultato è un codice più veloce: nei test, iterare su una collezione (insieme di elementi organizzati e gestiti come un unico oggetto) con un ciclo for
può diventare fino a 3 volte più rapido rispetto a .NET 9. Anche l’iterazione con foreach
migliora notevolmente rispetto al passato.
In C#, ogni accesso a un array viene controllato per evitare accessi fuori limite, evitando errori di memoria. Tali controlli aggiungono però istruzioni extra. .NET 10 analizza il codice e rimuove i controlli non necessari.
Il risultato finale è che le applicazioni girano più velocemente, consumano meno memoria e sfruttano meglio le risorse, cosa ideale per cloud, microservizi e software ad alte prestazioni.
.NET 10 sarà a breve pubblicato in versione finale nella pagina di download sul sito Microsoft.