2012-05-28 11 views
10

Avrei bisogno di memorizzare una stringa di codice lingua, come "en", che conterrà sempre 2 caratteri.Come vengono memorizzati i tipi String e Char in memoria in .NET?

È meglio definire il tipo "String" o "Char"?

private string languageCode; 

vs

private char[] languageCode; 

o c'è un altro, l'opzione migliore?

Come vengono memorizzati questi 2 elementi? quanti byte o bit saranno assegnati a loro quando i valori sono assegnati?

+5

Avete effettivamente dimostrato a te stesso che questo è ancora un problema? Ho raramente trovato il bisogno di preoccuparmi della memoria quando uso le stringhe, specialmente quelle piccole. Se non si presenta come un problema, non preoccuparti finché non lo è. È una soluzione facile in un secondo momento se le stringhe ti causano un problema di memoria. Altrimenti usa una stringa e non pensare nemmeno ai problemi di memoria. –

+0

Ho una logica molto intensa che memorizza migliaia di questi in memoria, quindi ogni piccolo aiuto. –

+0

@William Se le prestazioni sono così importanti, perché non dichiarare un 'enum LanguageCode: short' e salvare 2 byte? –

risposta

8

Come sono memorizzati

Sia il string e la char[] vengono memorizzati sul mucchio - in modo di memorizzazione è la stessa. Internamente suppongo che un string sia semplicemente una cover per char[] con lotti di codice aggiuntivo per renderlo utile per voi.

Anche se si hanno molte stringhe ripetute, è possibile utilizzare Interning per ridurre l'ingombro di memoria di tali stringhe.

La migliore opzione

mi favorirebbe stringa - è immediatamente più evidente ciò che il tipo di dati è e come si intende utilizzarlo. Le persone sono anche più abituate ad usare le stringhe, quindi la manutenibilità non ne risentirà. Beneficerai enormemente anche di tutto il codice che è stato fatto per te. Microsoft ha anche fatto un grande sforzo per assicurarsi che il tipo string non sia un maiale performante.

L'allocazione Dimensioni

Non ho idea di quanto è allocato, credo che le stringhe sono abbastanza efficienti, nel senso che solo allocare sufficiente per memorizzare i caratteri Unicode - in quanto sono immutabili è sicuro di fare questo . Anche gli array non possono essere ridimensionati senza allocare lo spazio in una nuova matrice, quindi presumo nuovamente che afferrino solo ciò di cui hanno bisogno.

Overhead of a .NET array?

Alternative

Sulla base delle informazioni che ci sono solo 20 codici di lingua e le prestazioni è la chiave, si potrebbe dichiarare la propria enum al fine di ridurre la dimensione necessaria per rappresentare i codici:

enum LanguageCode : byte 
{ 
    en = 0, 
} 

Questo avverrà solo 1 byte anziché 4+ per due char (in un array), ma limita la gamma di disponi e LanguageCode valori nell'intervallo di byte - che è più che sufficiente per 20 articoli.

È possibile visualizzare la dimensione dei tipi di valore utilizzando l'operatore sizeof(): sizeof(LanguageCode). Le enumerazioni non sono altro che il tipo sottostante sotto il cappuccio, sono predefinite per int, ma come puoi vedere nel mio esempio di codice puoi cambiarlo "ereditando" un nuovo tipo.

+0

Non si esplicitano internamente le stringhe in .Net; sono internati per te implicitamente dalla loro semplice dichiarazione. Inoltre, stringhe e array di caratteri sono estremamente diverse in .Net, dato che gli array char sono strutture mutevoli sul mucchio, o anche la pila a seconda di come li avete dichiarato, mentre le stringhe sono immutabili e come l'articolo si è collegato alle note, costruire up and build up e build up nel pool interno piuttosto che la normale memoria .Net Framework - significa che possono essere molto dispendiosi. –

+0

@ChrisMoschini Non tutte le stringhe sono internate. I letterali sono internati, ma non c'è molto altro. Se prendi una stringa come input, leggila da un file di risorse o da un'altra fonte che non sono internati. Devi internarli manualmente. È interessante notare che la mia risposta non ha nemmeno indicato in alcun modo. –

+0

Dipende da come viene scritto il codice, ad esempio se si cerca un gruppo di bit di stringa dichiarati nel codice, si finisce comunque con un gruppo di stringhe internate. Ma l'importante problema prestazionale è quello di gettare tonnellate di stringhe intermedie non necessarie sul mucchio quando sai che non ne hai bisogno: un singolo array di char è sempre molto più economico in termini di memoria, e se scrivi il tuo codice simile al interni di Regex, più economici per CPU. Meno mem utilizzati in .Net significa anche meno GC, che ha un altro vantaggio della CPU. –

0

Se si desidera memorizzare esattamente 2 caratteri, e lo fa in modo più efficiente, utilizzare una struct:

struct Char2 
{ 
public char C1, C2; 
} 

Utilizzando questa struct generalmente non causare nuove allocazioni heap. Ottimizzerà semplicemente un oggetto esistente (con la quantità minima possibile) o consumerà uno spazio di stack che è molto economico.

+0

Le allocazioni degli heap dipendono interamente da * dove * si dichiara la struttura. Sarà in pila solo se dichiarato all'interno di metodi/proprietà. All'interno delle classi sarà nel mucchio, con il resto dei membri della classe. –

+0

Non causerà un'assegnazione * nuova *. Otterrà semplicemente un oggetto esistente (con la quantità minima possibile). – usr

+0

Sì true, ma le allocazioni di heap sono in genere molto veloci e non dovrebbero essere inizialmente preoccupate. Detto questo, una struttura di 'struct LanguageCode' è una buona opzione. –

4

Risposta breve: Usa stringa

Risposta lunga:

private string languageCode; 

stringhe AFAIK sono memorizzati come una lunghezza prefissata array di caratteri. Un oggetto String viene istanziato sull'heap per mantenere questo array raw. Ma un oggetto String è molto più di un semplice array consente operazioni di stringa di base come confronto, concatenazione, sottostringa estrazione, la ricerca ecc

Mentre

private char[] languageCode; 

sarà memorizzato come una matrice di caratteri cioè un oggetto Array verrà creato nell'heap e quindi verrà utilizzato per gestire i tuoi personaggi. Ma ha ancora un attributo di lunghezza che viene memorizzato internamente quindi non ci sono risparmi apparenti in memoria rispetto a una stringa. Anche se presumibilmente una matrice è più semplice di una stringa e potrebbe avere un numero inferiore di variabili interne che offrono quindi una minore impronta di memoria (è necessario verificarlo).

Ma OTOH si perde la capacità di eseguire operazioni sulle stringhe su questo array char. Anche le operazioni come il confronto delle stringhe diventano ingombranti ora. Per farla breve, usa una stringa!

1

Come sono questi 2 memorizzati nella memoria? quanti byte o bit saranno assegnati a loro quando i valori sono assegnati?

Ogni esempio in .NET viene memorizzato come segue: uno IntPtr campo -sized per l'identificatore tipo; un altro per il blocco sull'istanza; il resto è dati del campo di istanza arrotondati per eccesso a un importo di IntPtr. Quindi, su una piattaforma a 32 bit ogni esempio occupa di dati di campo 8 byte +.

Questo vale sia per un string sia per un char[]. Entrambi memorizzano la lunghezza dei dati come un intero di dimensioni IntPtr, seguito dai dati effettivi. Così, due caratteri string e due caratteri char[], su una piattaforma a 32 bit, occuperanno 8 + 4 + 4 = 16 byte.

L'unico modo per ridurre questo quando si memorizza esattamente due caratteri è quello di memorizzare i caratteri effettivi, o una struttura che contiene i caratteri, in un campo o un array. Tutti questi consumerebbe solo 4 byte per i caratteri:

// Option 1 
class MyClass 
{ 
    char Char1, Char2; 
} 

// Option 2 
class MyClass 
{ 
    CharStruct chars; 
} 
... 
struct CharStruct { public char Char1; public char Char2; } 

MyClass finirà usando 8 byte (su una macchina a 32 bit) per esempio, più 4 byte per i caratteri.

// Option 3 
class MyClass 
{ 
    CharStruct[] chars; 
} 

Questa utilizzerà 8 byte per l'overhead MyClass, più 4 byte per il charsriferimento, più 12 byte per l'overhead della matrice, più 4 byte per CharStruct nella matrice.

+0

Interessante. Da dove hai preso questa informazione? – kristianp

+1

@kristianp Molte di queste informazioni provengono da questo articolo di MSDN: https://msdn.microsoft.com/en-us/magazine/cc163791.aspx (scorrere verso il basso fino alla Figura 6) –

0

Corde infatti hanno un overhead dimensioni di una lunghezza puntatore, cioè 4 byte per un processo a 32 bit, 8 byte per un processo a 64 bit. Ma poi di nuovo, gli archi offrono molto di più in cambio degli array di carbone.

Se l'applicazione utilizza molte corde corte e non è necessario utilizzare le loro proprietà e metodi delle stringhe che spesso, si potrebbe probabilmente sicuro un paio di byte di memoria. Ma se vuoi usarne uno come stringa, devi prima creare una nuova istanza di stringa. Non riesco a vedere come questo ti aiuterà a conservare abbastanza memoria per valerne la pena.

Problemi correlati