2013-01-04 12 views
14

Stavo passando per l'API della classe String e sembra che ci sia una potenziale perdita di memoria causata dal metodo della sottostringa poiché condivide lo stesso array di caratteri della stringa originale.Perdita di memoria potenziale del metodo String.substring Java?

Se la stringa originale è enorme, la stringa piccola restituita dalla sottostringa può impedire la stringa originale (con il backup di array di grandi dimensioni) dalla raccolta dati obsoleti in Java.

Qualsiasi pensiero o ho letto l'API sbagliato.

+2

Questa non è tecnicamente una perdita di memoria, poiché l'array di caratteri è ancora referenziato e potrebbe essere raccolto in seguito quando tutte le stringhe che lo fanno riferimento vengono raccolte. Parte dell'array di caratteri potrebbe non essere più utilizzata, ma ciò non lo rende una perdita. – cdhowie

+1

se si dispone di una stringa 100 ogni 100 MB e si dispone di una sottostringa (0,1) si tiene tecnicamente quel valore [] utilizzato nella classe String e mai nell'applicazione stringhe enormi sono idonee per la garbage collection –

+1

miglior collegamento http://javarevisited.blogspot.com/2012/03/why-character-array-is-better-than.html – Premraj

risposta

17

è un potenziale per una perdita di memoria, se si prende una sottostringa di una stringa considerevole e non si effettua una copia (di solito tramite il costruttore String(String)).

Si noti che questo è cambiato dal Java 7u6. Vedere http://bugs.sun.com/view_bug.do?bug_id=4513622.

Le ipotesi originali sull'oggetto String che implementano uno flyweight pattern non sono più considerate valide.

Vedere this answer per ulteriori informazioni.

+0

entrambe le strategie sono valide. l'impl originale andava bene; la nuova impl va bene. ma non è corretto cambiare l'impl .... è una rottura sorprendente di compatibilità. non potevano averlo fatto per la ragione apparente. c'è qualcos'altro che sta succedendo. – irreputable

+0

@irreputable Questo era certamente un dettaglio di implementazione che non faceva parte della specifica => non avrebbe dovuto essere invocato. Il cambiamento è stato fatto per motivi di prestazioni. – assylias

+2

@assylias che è più di una sborsata. le persone hanno stabilito che substring()/trim() è O (1). cambiarlo silenziosamente in O (n) non è molto bello. E come si scrive codice che si comporta in modo coerente su diverse versioni di Java? – irreputable

4
  1. E 'stato il caso fino Java 7u6 - si dovrebbe in genere affrontare la questione facendo:

    String sub = new String(s.substring(...)); // create a new string 
    

    che rimuove in modo efficace la dipendenza e la stringa originale è ora disponibile per GC. Questo è comunque uno degli unici scenari in cui l'uso del costruttore di stringhe ha senso.

  2. Dal Java 7u6, viene creata una nuova stringa e non vi è più alcun problema di memoria.

+0

sì ma crea un nuovo problema. se si 'taglia()' su uno spazio bianco, che è un caso molto comune, si finisce per copiare i caratteri 'N-1'. – irreputable

+1

@irreputable È sempre possibile trovare casi d'angolo in cui si comportano peggio. L'obiettivo di un ilbraccio per scopi generici è di ottenere buoni risultati * in media * e sembra che siano stati presi in considerazione molti casi d'uso diversi prima di apportare tale modifica. – assylias

+0

Anche copiare i caratteri è * molto * veloce (non dicendo che non è costato). – assylias

0

In Java 7, sottoStringa di stringa viene modificato per:

/** 
    * Returns a new string that is a substring of this string. The 
    * substring begins with the character at the specified index and 
    * extends to the end of this string. <p> 
    * Examples: 
    * <blockquote><pre> 
    * "unhappy".substring(2) returns "happy" 
    * "Harbison".substring(3) returns "bison" 
    * "emptiness".substring(9) returns "" (an empty string) 
    * </pre></blockquote> 
    * 
    * @param  beginIndex the beginning index, inclusive. 
    * @return  the specified substring. 
    * @exception IndexOutOfBoundsException if 
    *    <code>beginIndex</code> is negative or larger than the 
    *    length of this <code>String</code> object. 
    */ 
    public String substring(int beginIndex) { 
     if (beginIndex < 0) { 
      throw new StringIndexOutOfBoundsException(beginIndex); 
     } 
     int subLen = value.length - beginIndex; 
     if (subLen < 0) { 
      throw new StringIndexOutOfBoundsException(subLen); 
     } 
     return (beginIndex == 0) ? this : new String(value, beginIndex, subLen); 
    } 

Quindi, ogni volta che si fanno SOTTOSTRINGA con beginIndex NON uguale a 0, abbiamo nuovo oggetto String.

Problemi correlati