JavaRush /Java-Blog /Random-DE /substring(..) hat mich verfolgt
IgorBrest
Level 33

substring(..) hat mich verfolgt

Veröffentlicht in der Gruppe Random-DE
Tatsächlich habe ich mir aus Gründen des Themas erlaubt, mich mit String.substring(..) zu befassen. Und ich bin wahrscheinlich zu unerwarteten Ergebnissen gekommen, die ich mit euch, liebe Javorashoviten, teilen möchte. Präsentieren Sie es sozusagen Ihrem Urteil. Also. Es gibt eine Anweisung, dass eine mit der Methode substring(..) erstellte Zeichenfolge das Zeichenarray der ursprünglichen Zeichenfolge verwendet. Hier ist insbesondere ein Auszug aus dem kürzlich gelesenen Artikel „Java Reference. Static Strings“ der angesehenen Artikel :
Es gibt einen Hinweis zur Teilstring-Methode: Der zurückgegebene String verwendet dasselbe Byte-Array wie der Original
Und natürlich Javarash-Vorlesungen. Hier sind Zitate vom 22. Dezember:
Wenn wir mit der Substring-Methode einen Teilstring erstellen, wird ein neues String-Objekt erstellt. Doch anstatt einen Verweis auf ein Array mit einem neuen Zeichensatz zu speichern, speichert dieses Objekt einen Verweis auf den alten Zeichen-Array und speichert gleichzeitig zwei Variablen, mit denen es bestimmt, welcher Teil des ursprünglichen Zeichen-Arrays dazu gehört. ... Beim Erstellen eines Teilstrings wird das Zeichenarray nicht in ein neues String-Objekt kopiert. Stattdessen speichern beide Objekte einen Verweis auf dasselbe Zeichenarray. Aber! Das zweite Objekt speichert zwei weitere Variablen, die enthalten, welche und wie viele Zeichen dieses Arrays darauf geschrieben werden. ... Wenn Sie also eine Zeichenfolge mit einer Länge von 10.000 Zeichen nehmen und daraus 10.000 Teilzeichenfolgen beliebiger Länge erstellen, beanspruchen diese „Teilzeichenfolgen“ sehr wenig Speicher, weil Das Zeichenarray wird nicht dupliziert. Zeichenfolgen, die viel Platz beanspruchen sollten, belegen nur ein paar Bytes.
alles ist klar geschrieben, sogar gekaut. Aber da ich versuche, meine Englischkenntnisse zu verbessern, greife ich oft auf die offizielle Dokumentation zurück, und irgendwie konnte ich keine Bestätigung für diese Tatsache finden ... Da ich dies auf meine Nachlässigkeit zurückführte, schaute ich mir trotzdem den Quellcode von an substring() (dank IDEA können Sie dies mit einem Klick auf eine Schaltfläche tun). public String substring(int beginIndex, int endIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > value.length) { throw new StringIndexOutOfBoundsException(endIndex); } int subLen = endIndex - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); } Fasziniert ging ich weiter: * Allocates a new {@code String} that contains characters from a subarray * of the character array argument. The {@code offset} argument is the * index of the first character of the subarray and the {@code count} * argument specifies the length of the subarray. The contents of the * subarray are copied; subsequent modification of the character array does * not affect the newly created string. public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count < 0) { throw new StringIndexOutOfBoundsException(count); } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); } Dabei ist Arrays.copyOfRange eine native Methode, die eine Kopie eines Arrays von char zurückgibt ... Ziemlich trivialer Code, und es schien mir offensichtlich, dass einfach eine neue Zeile mit einem neuen Satz von Zeichen erstellt wird. oder ich habe etwas nicht berücksichtigt ... Da ich also nicht ganz an meine Schlussfolgerungen glaubte, beschloss ich, diesen Teilstring () irgendwie zu testen und mich dabei auf einen Satz aus der Vorlesung zu stützen:
Wenn Sie also eine Zeichenfolge mit einer Länge von 10.000 Zeichen nehmen und daraus 10.000 Teilzeichenfolgen beliebiger Länge erstellen, beanspruchen diese „Teilzeichenfolgen“ sehr wenig Speicher ...
nur statt 10_000 machen wir sofort 100_000_000, warum Zeit mit Kleinigkeiten verschwenden? Ich habe schnell den folgenden Code eingegeben: und Folgendes ist passiert: d. h. Jedes Mal, wenn Sie mit bigString.substring(..) eine neue Unterzeichenfolge erstellen, wird das Zeichenarray DUPLIZIERT. Wie sonst können wir einen solchen Anstieg des Speicherverbrauchs erklären? Danach hatte ich persönlich keine Zweifel mehr an der Funktionsweise der Methode String.substsring(). Was ist mit Ihnen? public class Test { public static void main(String[] args) { System.out.println("Начинаем:"); print(); System.out.println("********************************"); char[]big=new char[100_000_000];//создаем нормальный такой массив int j=0;//и заполняем этот массив всякой ерундой for (int k=0;k list=new ArrayList<>();//здесь будут ссылки на строки, что бы сборщик мусора не удалял //не используемые, по его мнению, строки. System.out.println("************************************"); System.out.println("Теперь будем создавть подстроки с помощью substring(..) и наблюдать," + "что же происходит с памятью"); for (int i = 2; i <10; i++) { //создаем подстроку, используя метод String.substring(..) String sub= bigString.substring(1,bigString.length()-1); //если этот метод не создает völlig новый массив символов, а только пользуется //исходным из bigString // то при создании новой строки sub мы не будем наблюдать ощутипый расход памяти list.add(sub);//эти ссылки мы должны где нибудь хранить, иначе сборщик мусора //избавится от неипользуемых объктов String System.out.print(String.format("Создаем %d-ую подстроку, при этом ", i - 1)); print(); } System.out.println("***************************************"); print(); } static void print(){ System.out.println("Памяти используется "+(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory())/1024/1024 + " mb"); } } Начинаем: Памяти используется 0 mb ******************************** создал большую строку bigString на основе массива big. Теперь: Памяти используется 382 mb ************************************ Теперь будем создавть подстроки с помощью substring(..) и наблюдать,что же происходит с памятью Добавляем 1-ую подстроку, при этом Памяти используется 573 mb Добавляем 2-ую подстроку, при этом Памяти используется 763 mb Добавляем 3-ую подстроку, при этом Памяти используется 954 mb Добавляем 4-ую подстроку, при этом Памяти используется 1145 mb Добавляем 5-ую подстроку, при этом Памяти используется 1336 mb Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Arrays.java:3658) at java.lang.String. (String.java:201) at java.lang.String.substring(String.java:1956) at com.javarush.test.tests.Test.main(Test.java:42) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) Process finished with exit code 1
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION