Domanda

Ho letto di recente una discussione per quanto riguarda se lingue gestite sono più lenti (o più veloce) di lingue native (in particolare C # vs C ++). Una persona che ha contribuito alla discussione, ha detto che i compilatori JIT di lingue gestite sarebbero in grado di fare le ottimizzazioni per quanto riguarda i riferimenti che semplicemente non è possibile in lingue che usano i puntatori.

Quello che mi piacerebbe sapere è che tipo di ottimizzazioni che sono possibili su riferimenti e non su puntatori?

Si noti che la discussione era circa la velocità di esecuzione, non utilizzo della memoria.

È stato utile?

Soluzione

Ci sono alcuni vantaggi di compilazione JIT menzionata in Wikipedia:

  

Codice JIT offre generalmente molto migliori prestazioni rispetto interpreti. Inoltre, può in alcuni o molti casi offrono prestazioni migliori rispetto compilazione statica, come molte ottimizzazioni sono possibili solo in fase di esecuzione:

     
      
  1. La compilazione può essere ottimizzato per la CPU mirata e il modello di sistema operativo in cui l'applicazione viene eseguita. Per esempio JIT può scegliere istruzioni della CPU SSE2 quando rileva che la CPU li sostiene. Con un compilatore statico bisogna scrivere due versioni del codice, possibilmente utilizzando assembly inline.
  2.   
  3. Il sistema è in grado di raccogliere statistiche su come il programma è effettivamente in esecuzione in un ambiente che è in, e può riorganizzare e ricompilare per prestazioni ottimali. Tuttavia, alcuni compilatori statici possono anche prendere informazioni sul profilo come input.
  4.   
  5. Il sistema può fare ottimizzazioni del codice globali (ad esempio messa in linea delle funzioni di libreria) senza perdere i vantaggi di collegamento dinamico e senza le spese generali inerenti compilatori statici e linker. In particolare, quando si fa le sostituzioni in linea a livello mondiale, un compilatore statico deve inserire controlli in fase di esecuzione e garantire che una chiamata virtuale si sarebbe verificato se la classe reale dell'oggetto ridefinisce il metodo inline.
  6.   
  7. Anche se questo è possibile con garbage collection linguaggi compilati staticamente, un sistema di bytecode può più facilmente riorganizzare la memoria per un migliore utilizzo della cache.
  8.   

Non riesco a pensare a qualcosa legato direttamente all'uso di riferimenti al posto dei puntatori.

Altri suggerimenti

In C ++ ci sono due vantaggi di riferimenti relativi ad aspetti di ottimizzazione:

  1. Un riferimento è costante (si riferisce alla stessa variabile per tutta la sua vita)

    A causa di questo è più facile per il compilatore di dedurre che i nomi si riferiscono alle stesse variabili sottostanti - creando così opportunità di ottimizzazione. Non v'è alcuna garanzia che il compilatore farà meglio con i riferimenti, ma potrebbe ...

  2. Un riferimento viene assunto per riferirsi a qualcosa (non v'è alcun riferimento null)

    Un riferimento che "si riferisce a nulla" (equivalente al puntatore NULL) può essere creato, ma questo non è facile come creare un puntatore NULL. Per questo il controllo del riferimento per NULL può essere omessa.

Tuttavia, nessuno di questi vantaggi riporto direttamente alle lingue gestite, quindi non vedo la rilevanza di tale nel contesto del vostro argomento di discussione.

Nel parlare generale, i riferimenti permettono di fare riferimento allo stesso oggetto da luoghi diversi.

A 'puntatore' è il nome di un meccanismo per implementare i riferimenti. C ++, Pascal, C ... hanno i puntatori, C ++ offre un altro meccanismo (con un po 'gli altri casi d'uso) chiamato 'Riferimento', ma in sostanza queste sono tutte le implementazioni del concetto generale di riferimento.

Quindi, non v'è alcun motivo per cui riferimenti sono per definizione più veloce / più lento di puntatori.

La vera differenza è nell'uso di un JIT o un classico compilatore 'in anticipo': il JIT può tener conto dei dati che non sono disponibili per il compilatore up front. Non ha nulla a che fare con l'attuazione del concetto di 'riferimento'.

Altre risposte sono giuste.

vorrei solo aggiungere che qualsiasi ottimizzazione non farà un grido di differenza a meno che non sia in codice in cui il contatore di programma in realtà passa molto tempo, come in cicli stretti che non contengono chiamate di funzione (ad esempio confrontando le stringhe).

Un riferimento all'oggetto in un quadro gestito è molto diverso da un riferimento passato in C ++. Per capire che cosa li rende speciali, immaginare come il seguente scenario sarebbe stato gestito, a livello di macchina, senza riferimenti a oggetti garbage collection: Metodo "Foo" restituisce una stringa, che è memorizzato in varie collezioni e passato a diversi pezzi di codice. Una volta che ha bisogno di nulla la stringa di più, dovrebbe essere possibile per recuperare tutta la memoria utilizzata in riporlo, ma è chiaro quale parte del codice sarà l'ultimo a usare la stringa.

In un sistema non-GC, ogni collezione sia bisogno di avere la propria copia della stringa, oppure ha bisogno di tenere qualcosa che contiene un puntatore ad un oggetto condiviso che contiene i caratteri della stringa. In quest'ultimo caso, l'oggetto condiviso ha bisogno di sapere in qualche modo quando l'ultimo puntatore ad esso viene eliminato. Ci sono una varietà di modi in cui questo può essere manipolato, ma un elemento essenziale aspetto comune di tutti loro è che gli oggetti condivisi devono essere avvisati quando i puntatori a loro vengono copiati o distrutti. Tale comunicazione richiede lavoro.

In un sistema GC contrario, i programmi sono decorate con metadati dire che registra o parti di uno stack frame saranno utilizzati in qualsiasi momento per contenere riferimenti a oggetti radicate. Quando si verifica un ciclo di raccolta dei rifiuti, il garbage collector dovrà analizzare questi dati, di identificare e conservare tutti gli oggetti dal vivo, e Nuke tutto il resto. In tutti gli altri casi, invece, il processore può copiare, sostituire, shuffle, o distruggere i riferimenti a qualsiasi modello o una sequenza che vuole, senza dover comunicare qualsiasi degli oggetti coinvolti. Si noti che quando si usa il puntatore uso notifiche in un sistema multi-processore, se diversi fili possono copiare o distruggere riferimenti allo stesso oggetto, codice di sincronizzazione sarà necessario per rendere thread-safe notificazione richiesta. Al contrario, in un sistema GC, ciascun processore può cambiare le variabili di riferimento in qualsiasi momento senza dover sincronizzare le sue azioni con qualsiasi altro processore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top