JavaRush /Blogue Java /Random-PT /substring(..) me assombrou
IgorBrest
Nível 33

substring(..) me assombrou

Publicado no grupo Random-PT
Na verdade, pelo motivo do assunto, me permiti aprofundar em String.substring(..). E provavelmente cheguei a resultados inesperados, que decidi compartilhar com vocês, queridos Javorashovitas. Apresente-o ao seu julgamento, por assim dizer. Então aqui está. Há uma afirmação de que uma string criada usando o método substring(..) usa a matriz de caracteres da string original. Aqui, em particular, está um trecho do artigo recentemente lido "Java Reference. Static Strings" pelos respeitados artigos :
Há uma observação sobre o método substring - a string retornada usa a mesma matriz de bytes que a original
E, claro, Palestras Javarash. Aqui estão citações de 22 de dezembro:
Quando criamos uma substring usando o método substring, um novo objeto String é criado. Mas em vez de armazenar uma referência a um array com um novo conjunto de caracteres, este objeto armazena uma referência ao array de caracteres antigo e ao mesmo tempo armazena duas variáveis ​​​​com as quais determina qual parte do array de caracteres original pertence a ele. ... Quando uma substring é criada, a matriz de caracteres não é copiada para um novo objeto String. Em vez disso, ambos os objetos armazenam uma referência à mesma matriz de caracteres. Mas! O segundo objeto armazena mais duas variáveis, que contém quais e quantos caracteres deste array estão gravados nele. ... Portanto, se você pegar uma string de 10.000 caracteres e criar 10.000 substrings de qualquer comprimento a partir dela, essas “substrings” ocuparão muito pouca memória, porque a matriz de caracteres não está duplicada. Strings que deveriam ocupar muito espaço ocuparão apenas alguns bytes.
tudo está claramente escrito, até mastigado. Mas, como estou tentando aprimorar meu conhecimento de inglês, muitas vezes recorro à documentação oficial, e de alguma forma não consegui encontrar a confirmação desse fato... Atribuindo isso ao meu descuido, ainda olhei o código fonte do substring() (graças ao IDEA permite que você faça isso com um clique de um botão). 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); } Intrigado, fui além: * 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); } onde Arrays.copyOfRange é um método nativo que retorna uma cópia de um array de char... Código bastante trivial, e me pareceu óbvio que uma nova linha com um novo conjunto de caracteres é simplesmente criada. ou não levei algo em consideração... Então, não acreditando totalmente nas minhas conclusões, resolvi de alguma forma testar essa substring(), baseando-me em uma frase da palestra:
Portanto, se você pegar uma string de 10.000 caracteres e criar 10.000 substrings de qualquer comprimento a partir dela, então essas “substrings” ocuparão muito pouca memória...
só que em vez de 10_000 faremos imediatamente 100_000_000, por que perder tempo com ninharias. Eu rapidamente coloquei o seguinte código: e foi isso que aconteceu: ou seja. Cada vez que você cria uma nova substring usando bigString.substring(..), a matriz de caracteres é DUPLICADA. De que outra forma podemos explicar esse aumento no consumo de memória? Depois disso, eu pessoalmente não tive mais dúvidas quanto ao funcionamento do método String.substsring(). E você? 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
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION