2013-01-04 5 views
14

Ich ging durch die API der String-Klasse und sieht aus, als ob ein potenzieller Speicherverlust durch die Teilstring-Methode verursacht wird, da er dasselbe Zeichenarray wie der ursprüngliche String teilt.Java Stringstring-Methode potentielles Speicherleck?

Wenn die ursprüngliche Zeichenfolge sehr groß ist, kann die von der Teilzeichenfolge zurückgegebene Zeichenfolge die ursprüngliche Zeichenfolge (die von einem großen Array gesichert wird) aus der Speicherbereinigung in Java verhindern.

Irgendwelche Gedanken oder habe ich die API falsch gelesen.

+2

Dies ist technisch gesehen überhaupt kein Speicherleck, da das Zeichenarray immer noch referenziert ist und später gesammelt werden kann, wenn alle Zeichenfolgen, die darauf verweisen, gesammelt werden. Ein Teil des Zeichen-Arrays wird möglicherweise nicht mehr verwendet, aber das macht es nicht zu einem Leck. – cdhowie

+1

Wenn Sie eine 100 große Zeichenfolge alle 100 MB haben und Sie eine Teilzeichenfolge (0,1) haben, halten Sie technisch den Wert [] in String-Klasse und nie in der Anwendung sind große Zeichenfolgen für Garbage Collection geeignet –

+1

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

Antwort

17

Dort ist ein Potenzial für einen Speicherverlust, wenn Sie eine Teilzeichenfolge einer größeren Zeichenfolge und nicht eine Kopie (in der Regel über die String(String) Konstruktor) nehmen.

Beachten Sie, dass sich dies seit Java 7u6 geändert hat. Siehe http://bugs.sun.com/view_bug.do?bug_id=4513622. Die ursprünglichen Annahmen um das Objekt String, das eine flyweight pattern implementiert, werden nicht länger als gültig betrachtet.

Weitere Informationen finden Sie unter this answer.

+0

beide Strategien sind gültig. der ursprüngliche Impl war in Ordnung; Der neue Impl ist in Ordnung. aber es ist nicht in Ordnung, den Impl zu ändern .... es ist ein erstaunlicher Bruch der Kompatibilität. Sie hätten es aus dem offensichtlichen Grund nicht tun können. da ist noch etwas anderes. – irreputable

+0

@irreputable Dies war zugegebenermaßen ein Implementierungsdetail, das nicht Teil der Spezifikation war => es sollte nicht verlässlich sein. Die Änderung wurde aus Leistungsgründen vorgenommen. – assylias

+2

@assylias, das ist eher eine Ausrede. Leute haben festgestellt, dass substring()/trim() O (1) ist. es still zu O (n) zu ändern ist nicht sehr nett. Und wie schreibt man Code das sich bei verschiedenen Java Versionen konsistent verhält? – irreputable

4
  1. Es war der Fall bis Java 7u6 - Sie in der Regel mit dem Problem, indem Sie beschäftigen würden:

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

    , die effektiv entfernt die Abhängigkeit und die ursprüngliche Zeichenfolge ist jetzt für GC. Dies ist übrigens eines der wenigen Szenarien, in denen die Verwendung des String-Konstruktors sinnvoll ist.

  2. Seit Java 7u6 wird ein neuer String erstellt und es gibt kein Speicherproblem mehr.

+0

Ja, aber es schafft ein neues Problem. Wenn Sie einen weißen Bereich trimmen(), was ein sehr häufiger Fall ist, werden Sie 'N-1'-Zeichen kopieren. – irreputable

+1

@irreputable Sie können immer Eckfälle finden, in denen es schlechter abschneiden wird. Das Ziel einer allgemeinen Anwendung ist, im Durchschnitt gut * zu arbeiten, und es scheint, dass viele verschiedene Anwendungsfälle berücksichtigt wurden, bevor diese Änderung vorgenommen wurde. – assylias

+0

Kopieren von Zeichen ist auch * sehr * schnell (nicht zu sagen, es hat nicht gekostet). – assylias

0

In Java 7 wird String der Teilzeichen geändert:

/** 
    * 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); 
    } 

daher jedes Mal wenn Sie mit beginIndex- do Teilzeichenfolge nicht gleich 0, haben wir neues String-Objekt.