2016-02-11 21 views
9

Sto confrontando i vari modi di memorizzare uno String in java interrompendo un String nelle sue parti costitutive. Ho questo frammento di codice:Differenti dimensioni della rappresentazione di stringhe in Java

final String message = "ABCDEFGHIJ"; 
System.out.println("As String " + RamUsageEstimator.humanSizeOf(message)); 
System.out.println("As byte[] " + RamUsageEstimator.humanSizeOf(message.getBytes())); 
System.out.println("As char[] " + RamUsageEstimator.humanSizeOf(message.toCharArray())); 

Questo sta usando sizeof per misurare le dimensioni degli oggetti. I risultati mostrano sopra:

As String 64 bytes 
As byte[] 32 bytes 
As char[] 40 bytes 

Dato che un byte è 8 bit e un char è di 16 bit, perché sono i risultati non 10 byte e 20 byte rispettivamente?

Inoltre, qual è il sovraccarico per l'oggetto String che ne causa il doppio delle dimensioni del sottostante byte[]?

è usare

java version "1.8.0_60" 
Java(TM) SE Runtime Environment (build 1.8.0_60-b27) 
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode) 

su OSX

+2

Per ottenere una buona risposta, è necessario specificare la JVM esatto che si sta utilizzando. – biziclop

+0

Una stringa contiene anche: int offset, int hashcode, int length in oracle java, quelli di 12 byte, lasciando 2 byte per il puntatore all'array, presumo .. – Ferrybig

+0

@Ferrybig I tre campi 'int' si sommano solo 12 byte, ma esiste anche un'intestazione di oggetto. La dimensione del riferimento dell'array dipende dalla VM (32/64 bit) e dalle sue impostazioni (indipendentemente dal fatto che utilizzi puntatori compressi o meno). Poi c'è la questione dell'allineamento e ovviamente sarebbe bello sapere come funziona effettivamente RamUsageEstimator. (E Java 8 ha eliminato i campi 'offset' e' length'.) – biziclop

risposta

6

I dati seguenti sono per Hotspot/Java 8 - i numeri varieranno per altre versioni JVM/Java (ad esempio, in Java 7, String sono presenti due ulteriori campi int).

A new Object() occupa 12 byte di memoria (a causa di elementi interni come l'intestazione dell'oggetto).

una stringa ha (numero di byte tra parentesi):

  • un'intestazione oggetto (12),
  • un riferimento a un char[] (4 - OOP compressa assumendo in 64 bit JVM),
  • an int hash (4).

Vale a dire 20 byte ma gli oggetti vengono riempiti a multipli di 8 byte => 24. Quindi sono già 24 byte in cima al contenuto effettivo dell'array.

Il char[] ha un'intestazione (12), una lunghezza (4) e ogni carattere (10 x 2 = 20) riempito al successivo multiplo di 8 - o 40 in totale.

Il byte[] ha un colpo di testa (12), una lunghezza (4) e ogni byte (10 x 1 = 10) = 26, imbottito per il prossimo multiplo di 8 = 32.

Così otteniamo al vostro numeri.

Si noti inoltre che il numero di byte dipende dalla codifica si utilizza - se riprovare con message.getBytes(StandardCharsets.UTF_16) per esempio, vedrete che l'array di byte utilizza 40 byte invece di 32.


È possibile utilizzare jol per visualizzare l'utilizzo della memoria e confermare il calcolo sopra. L'uscita del char[] è:

OFFSET SIZE TYPE DESCRIPTION     VALUE 
     0  4  (object header)    01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
     4  4  (object header)    00 00 00 00 (00000000 00000000 00000000 00000000) (0) 
     8  4  (object header)    41 00 00 f8 (01000001 00000000 00000000 11111000) (-134217663) 
    12  4  (object header)    0a 00 00 00 (00001010 00000000 00000000 00000000) (10) 
    16 20 char [C.<elements>     N/A 
    36  4  (loss due to the next object alignment) 
Instance size: 40 bytes (reported by Instrumentation API) 

Così si può vedere l'intestazione di 12 (prime 3 linee), la lunghezza (linea 4), i caratteri (linea 5) e l'imbottitura (linea 6).

Allo stesso modo per la stringa (si noti che questo esclude la dimensione della matrice stessa):

OFFSET SIZE TYPE DESCRIPTION     VALUE 
     0  4  (object header)    01 00 00 00 (00000001 00000000 00000000 00000000) (1) 
     4  4  (object header)    00 00 00 00 (00000000 00000000 00000000 00000000) (0) 
     8  4  (object header)    da 02 00 f8 (11011010 00000010 00000000 11111000) (-134216998) 
    12  4 char[] String.value     [A, B, C, D, E, F, G, H, I, J] 
    16  4 int String.hash     0 
    20  4  (loss due to the next object alignment) 
Instance size: 24 bytes (reported by Instrumentation API) 
1

Ogni del test, stima le dimensioni di un Object. Nel primo caso un oggetto String, nel secondo un oggetto matrice byte e infine un oggetto matrice char. Ogni oggetto, come istanza di una classe, può contenere alcuni attributi privati ​​e altre cose del genere; quindi non puoi aspettarti qualcosa di meglio di: uno String di 10 caratteri, contiene almeno 10 caratteri, ognuno di 2 byte di lunghezza, quindi l'intera dimensione deve essere ≥20 byte, che è coerente con i risultati.

Per il confronto byte/carattere, si sbaglia, perché l'array di byte di una stringa fornisce tutti i byte per una determinata codifica. Potrebbe accadere che la codifica corrente usi più di un byte per un carattere.

Si può dare un'occhiata al codice sorgente Java per Object, String supporto di classe e array in JVM per capire cosa succede esattamente.

+0

Dove può essere trovato il codice sorgente della classe 'array' che hai menzionato? Mai conosciuto questa classe esisteva in Java – Ferrybig

+1

@Ferrybig Non c'è alcun codice sorgente. Tutte le classi di array sono sintetizzate dalla JVM come richiesto. – EJP

+0

Questo è un tipo built-in, con supporto speciale. –

Problemi correlati