Domanda

So che la boxe è un concetto popolare con molte informazioni disponibili su di esso, ma ho alcune domande a cui non riesco davvero a trovare le risposte:

1) Se la boxe porta alla conversione di un tipo di valore (struct) in un oggetto (tipo di riferimento) o tipo di riferimento, perché usare un tipo di valore che verrà inscatolato e incorrere in una penalità di prestazione? Sono consapevole dei vantaggi e dell'idoneità in alcuni casi di una struttura o di una classe. Si dice (1) che i valori (tipi di valore) tendono a vivere nello stack in uno spazio di archiviazione temporaneo, ma per quanto tempo? Se non ho bisogno del tipo, come posso assicurarmi che sia curato e smaltito in quel momento? O è qui che entra in gioco il modello usa e getta? Presumo che la ragione per usare una struttura sarà dovuta ai suoi benefici.

È interessante notare che se uso una struttura per memorizzare due stringhe e un campo DateTime, la struttura terrà insieme due riferimenti (stringhe) e DateTime. Ovviamente presumo che questo sia più veloce dei valori dispersi. C'è qualcosa di cui devo essere consapevole in questo progetto? (2).

1) http: //en.csharp-online .net / Classi, strutture e oggetti: boxe e unboxing

2) http://dotnetperls.com/Content/Struct-Examples.aspx

Ho fatto una ricerca qui per le risposte che cerco, ma senza fortuna. Di solito cerco su questo sito argomenti come GC, generici, gestione delle eccezioni, ecc., Poiché c'è molta saggezza da imparare e condividere.

Grazie per la (potenziale) educazione a tutti i poster! Si prega di scusare ogni potenziale ingenuità. Imparare gli interni mi porta piacevolmente a passare un po 'di tempo a capire IL, ecc. (Qualcosa da affrontare, presto).

È stato utile?

Soluzione

Se non si passa mai il tipo di valore a una variabile di riferimento, il boxing non si verificherà. Se non lo sai, rispondi alle seguenti domande :

  • Agisci come tipi primitivi.
  • Hanno una dimensione dell'istanza inferiore a 16 byte.
  • Sono immutabili.
  • La semantica del valore è desiderabile.

Di solito considero anche quale sia la durata di tale variabile. Se si tratta di una variabile locale utilizzata all'interno di un metodo, tenterei di utilizzare struct (altrimenti class).

Altri suggerimenti

È necessario utilizzare i tipi di valore a causa del loro vantaggio logico, non dei miglioramenti delle prestazioni. Detto questo, poiché i tipi di valore sono gestiti nello stack, non è necessario partecipare alla garbage collection. Se hai un tipo che viene costantemente creato e scartato (come un int, float, double, ecc.), Puoi ottenere un buon impulso trasformandoli in strutture. La cosa da fare attenzione è che dovresti davvero considerare questo solo se puoi anche rendere la struttura immutabile.

Un altro paio di cose da considerare -

Per prima cosa, vuoi assicurarti che le strutture siano immutabili (in generale). Per questo motivo, è buona norma non avere strutture contenenti tipi di riferimento. Le stringhe possono essere un'eccezione poiché sono immutabili in C #, ma in termini di una regola empirica generale per il design, sarei diffidente di questo.

In secondo luogo, c'è un altro caso d'uso per le strutture che non è stato menzionato finora: un gran numero di piccoli oggetti. Se si dispone di un ampio elenco o di una serie di piccoli oggetti, le strutture offrono una coerenza della cache notevolmente migliore e sono assolutamente critiche. Questo è il motivo per cui la maggior parte dei motori 3D usa strutture per punti / vettori - tendono ad avere grandi matrici di punti per vertici, ecc.

Questo è qualcosa su cui vale la pena prestare attenzione se le prestazioni sono una parte importante dell'applicazione. Ad esempio, in una delle mie app, la modifica di un singolo tipo da una classe a una struttura ha permesso di risparmiare il 40% su un processo di lunga durata (tempo di esecuzione di 5 minuti). Avere gli oggetti vicini nella memoria se li usi ripetutamente in calcoli matematici pesanti può fornire enormi guadagni.

Ora - nel tuo caso, avere 2 stringhe e un DateTime probabilmente non vedrà alcun miglioramento da questo. Il tipo di routine che funzionerebbe sulle stringhe probabilmente non sta eseguendo calcoli pesanti (si spera), ovvero: trasformando mezzo milione di punti nello spazio o facendo una soluzione a matrice di grandi dimensioni, ecc.

Infine, noterai che .net3.5sp1 ha reso le strutture molto più utili. Prima di 3.5sp1 (su x86), non c'erano allineamenti di metodi con chiamate struct. Ciò ha limitato i guadagni di prestazione possibili tramite le strutture. L'aggiornamento del framework può rendere il vecchio codice struct molto, molto più veloce (in alcuni casi).

Non hai sempre bisogno del pugilato, e con i generici c'è poco bisogno di questo.
La memoria utilizzata dai tipi di valore (struct è un tipo di valore) verrà rivendicata come
non appena il metodo termina / ritorna e non è necessario fare nulla affinché ciò accada.

I tipi di valore dichiarati come membri dell'istanza rimarranno in memoria fino all'oggetto
viene eliminato dal GC.

I tipi di riferimento vengono mantenuti nell'heap gestito.
I tipi di riferimento istanziati all'interno di un metodo verranno eliminati dalla
garbage collector quando nessun oggetto contiene un riferimento ad esso.

GC funziona da solo e per la maggior parte dovresti lasciarlo da solo.
Non è possibile prevedere quando un oggetto verrà eliminato dal GC.

Il modello Dispose viene utilizzato sui tipi di riferimento ma non imporrà a GC di eliminare
un oggetto. Di solito viene utilizzato per liberare risorse non gestite.

Per i valori nello stack considerare quanto segue:
Supponiamo che tu abbia un semplice programma con tre metodi, come di seguito:
Quando viene eseguito questo programma, viene eseguito il metodo Main e così via. Segui la
numeri di seguito:


Main
{
   // (0) Stack is empty
   int firstInt = 0;
   // (1) Stack now contains:
   //                     firstInt
   DoSomething1();
   // (7) Stack still contains:
   //                     firstInt
}
// Program ends

DoSomething()
{
   int anInteger = 0; 
   // (2) Stack now contains:
   //                    anInteger
   //                    firstInt
   DoMore()
   // (5) Stack now contains:
   //                     anInteger
   //                     firstInt
}
// (6) anInteger goes out of scope

DoMore
{
  int anotherInteger = 1; 
   // (3) Stack now contains:
   //                     anotherInteger
   //                     anInteger
   //                     firstInt
}
// (4) anotherInteger goes out of scope

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