2016-07-15 36 views
19

Sono consapevole se si effettuaIn che modo JVM riutilizza le sottostringhe String internate?

for (condition) { 
    String s = "hi there"; 
} 

Solo un String istanza viene creato in tutte le iterazioni, a differenza String s = new String("hi there"); che creerà una nuova istanza in ogni iterazione.

Ma, leggendo Effective Java da Joshua Bloch: capitolo 2 punto 5 (pagina 20) si afferma:

Inoltre, è garantito che l'oggetto sarà riutilizzato da qualsiasi altro codice in esecuzione nello stesso la macchina virtuale che succede a contiene la stessa stringa letterale [JLS, 3.10.5].

per quanto ne so che non dice capita di essere la stessa stringa letterale, si dice contiene.

La lettura di [JLS, 3.10.5] non riesce a trovare alcun riferimento esatto a questo e ho un dubbio.

Dare questo frammento:

String s1 = "hi "; 
String s2 = "there"; 
String s3 = "hi there"; 

Come molti casi vengono creati?

  • 3 istanze (quindi, la frase non è proprio esatta).
  • 2 casi, s1 e s2 (poi s3 viene creato il riutilizzo s1 e s2 riferimenti)
+1

Probabilmente significa "la macchina virtuale contiene ..", non la stringa contiene un'altra stringa –

+1

Non sono sicuro, quindi un commento invece di una risposta. Ma penso che il "contenere" sia parzialmente sbagliato e il tuo esempio in effetti fornisce tre esempi. – glglgl

+0

@glglgl in realtà è ciò che * la mia logica * dice, ma può essere JVM abbastanza intelligente da creare 's3' come riferimento a' s1' + 's2' ?? –

risposta

17

Il JLS non garantisce alcun riutilizzo dei sotto-stringhe di sorta. Il "contenere" qui è solo inteso che la classe menziona lo stesso letterale stringa da qualche parte. È non utilizzato nel senso "sottostringa di".

+2

Specificamente _ "qualsiasi altro codice [..] che contiene la stessa stringa letterale **" _ (enfasi del mio) –

+1

quando si dice * non garantisce alcun riutilizzo di sotto-stringhe * significa che può accadere qualche volta? –

+3

@JordiCastilla: Non penso che nessuna VM corrente riutilizza le sottostringhe, ma è possibile (e le precedenti iterazioni di OpenJDK, ad esempio, qualche volta condividevano il char sottostante [] quando due stringhe erano sottostringhe l'una dell'altra). Nota che * dovresti * ancora osservare le istanze separate di 'String' e non ci sono API pubbliche per rilevare se ciò sta accadendo (cioè non saresti in grado di dirlo senza alcuni trucchi di riflessione). –

3

Ogni file di classe contiene un elenco di tutte le stringhe letterali o altre costanti utilizzate all'interno di tale classe (ad eccezione di piccole costanti numeriche che sono incorporate nel flusso di istruzioni). Se l'elemento 19 nell'elenco è la stringa letterale "Freddy" e la variabile locale Fred ha un indice di 6, quindi il bytecode generato per Fred="Freddy"; sarà probabilmente ldc 19/astore 6.

Quando una classe viene caricata, il sistema costruirà una tabella di tutte le costanti e - per quelle di tipo di riferimento - gli oggetti identificati in tal modo. Se non si conosce l'esistenza di una stringa letterale, il sistema ne aggiungerà uno alla tabella interna e memorizzerà un riferimento. Quando si genera codice macchina, lo ldc 19 verrà sostituito con un'istruzione per caricare il riferimento appropriato.

Che cosa è importante è che per il momento qualsiasi del codice in una classe corre, gli oggetti sono stati creati per tutte le stringhe in esso, in modo da una dichiarazione come Fred="Freddy"; si limiterà a memorizzare un riferimento a un String oggetto già esistente contenente Freddy , piuttosto che creare un nuovo oggetto String.

2

Se s3 riutilizzati s1 e s2 casi, quindi s3 non sarebbe fisicamente rappresentato come un array di caratteri continua, ma sarebbe piuttosto essere un composito di StringString s oggetti.

Ora l'impatto delle prestazioni sull'accesso ai singoli caratteri all'interno di un accesso basato su stringhe di stringhe implica effettivamente il confronto del valore dell'indice con la dimensione della prima stringa, quindi il calcolo dell'offset che diventerebbe indice per la seconda stringa, ecc. .

in realtà, il contrario potrebbe avere senso: solo un sottostante sequenza char può essere destinata per "hi there" (s3), e s1 e s2 potrebbe semplicemente memorizzare le loro lunghezze e indirizzi del primo carattere all'interno di tale stringa. Ma presumo che sarebbe un lavoro complesso e costoso per jvm identificare i candidati "incorporabili" e che il costo supererebbe i potenziali benefici.

+1

Bene, prima di Java 7 il metodo 'substring' era implementato in modo da restituire una stringa supportata dall'array di caratteri della stringa originale, ma anche quello è stato eliminato perché causava più danni che benefici (testi di grandi dimensioni potrebbero essere tenuto in vita tenendo un riferimento ad una piccola sottostringa, ad esempio) – Hulk

+1

@Hulk: è stato [modifica in Java7update6] (http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4513622). Non è solo un problema gc; richiede che ogni stringa porti un campo 'offset' e' length' al solo scopo di una singola operazione, 'sottostringa'. Inoltre, la funzionalità di deduplicazione delle stringhe delle JVM recenti beneficia del layout semplificato degli oggetti come un singolo 'cas' sul campo' value' è sufficiente. – Holger

Problemi correlati