JavaRush /Blog Java /Random-FR /la sous-chaîne(..) m'a hanté
IgorBrest
Niveau 33

la sous-chaîne(..) m'a hanté

Publié dans le groupe Random-FR
En fait, pour la raison du sujet, je me suis permis de me plonger dans String.substring(..). Et je suis probablement arrivé à des résultats inattendus, que j'ai décidé de partager avec vous, chers Javorashovites. Présentez-le à votre jugement, pour ainsi dire. Alors voilà. Il existe une instruction selon laquelle une chaîne créée à l'aide de la méthode substring(..) utilise le tableau de caractères de la chaîne d'origine. Voici notamment un extrait de l'article récemment lu "Java Reference. Static Strings" par des articles respectés :
Il y a une note sur la méthode de sous-chaîne - la chaîne renvoyée utilise le même tableau d'octets que celui d'origine
Et bien sûr, les conférences Javarash. Voici les citations du 22 décembre :
Lorsque nous créons une sous-chaîne à l’aide de la méthode substring, un nouvel objet String est créé. Mais au lieu de stocker une référence à un tableau avec un nouveau jeu de caractères, cet objet stocke une référence à l'ancien tableau de caractères et stocke en même temps deux variables avec lesquelles il détermine quelle partie du tableau de caractères d'origine lui appartient. ... Lorsqu'une sous-chaîne est créée, le tableau de caractères n'est pas copié dans un nouvel objet String. Au lieu de cela, les deux objets stockent une référence au même tableau de caractères. Mais! Le deuxième objet stocke deux autres variables, qui contiennent lesquels et combien de caractères de ce tableau y sont écrits. ... Par conséquent, si vous prenez une chaîne de 10 000 caractères et en créez 10 000 sous-chaînes de n'importe quelle longueur, alors ces « sous-chaînes » occuperont très peu de mémoire, car le tableau de caractères n'est pas dupliqué. Les chaînes qui devraient occuper une tonne d’espace n’occuperont que quelques octets.
tout est clairement écrit, même mâché. Mais comme j'essaie d'améliorer ma connaissance de l'anglais, je me tourne souvent vers la documentation officielle, et d'une manière ou d'une autre, je n'ai pas pu trouver de confirmation de ce fait... Attribuant cela à ma négligence, j'ai quand même regardé le code source de substring() (grâce à IDEA, vous pouvez le faire en un seul clic). 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); } Intrigué, je suis allé plus loin : * 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); } où Arrays.copyOfRange est une méthode native qui renvoie une copie d'un tableau à partir de char... Code assez trivial, et il m'a semblé évident qu'une nouvelle ligne avec un nouvel ensemble de caractères est simplement créée. ou je n'ai pas pris en compte quelque chose... Alors, ne croyant pas entièrement à mes conclusions, j'ai décidé de tester d'une manière ou d'une autre cette substring(), en m'appuyant sur une phrase de la conférence :
Par conséquent, si vous prenez une chaîne de 10 000 caractères et en créez 10 000 sous-chaînes de n'importe quelle longueur, alors ces « sous-chaînes » occuperont très peu de mémoire...
seulement au lieu de 10_000, nous gagnerons immédiatement 100_000_000, pourquoi perdre du temps en bagatelles. J'ai rapidement ajouté le code suivant : et voici ce qui s'est passé : c'est-à-dire Chaque fois que vous créez une nouvelle sous-chaîne à l'aide de bigString.substring(..), le tableau de caractères est DUPLIQUÉ. Sinon, comment expliquer une telle augmentation de la consommation de mémoire ? Après cela, personnellement, je n'ai plus eu aucun doute sur le fonctionnement de la méthode String.substsring(). 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); //если этот метод не создает fully новый массив символов, а только пользуется //исходным из 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
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION