JavaRush /Java Blog /Random-IT /substring(..) mi perseguitava
IgorBrest
Livello 33

substring(..) mi perseguitava

Pubblicato nel gruppo Random-IT
In realtà, per motivi di argomento, mi sono permesso di approfondire String.substring(..). E probabilmente sono arrivato a risultati inaspettati, che ho deciso di condividere con voi, cari Javorashoviti. Presentalo al tuo giudizio, per così dire. Quindi eccolo qui. Esiste un'istruzione secondo cui una stringa creata utilizzando il metodo substring(..) utilizza l'array di caratteri della stringa originale. Ecco, in particolare, un estratto dall'articolo letto di recente "Java Reference. Static Strings" dagli articoli rispettati :
C'è una nota sul metodo sottostringa: la stringa restituita utilizza lo stesso array di byte di quello originale
E, naturalmente, le Javarash Lectures. Ecco le citazioni del 22 dicembre:
Quando creiamo una sottostringa utilizzando il metodo substring, viene creato un nuovo oggetto String. Ma invece di memorizzare un riferimento a un array con un nuovo set di caratteri, questo oggetto memorizza un riferimento al vecchio array di caratteri e allo stesso tempo memorizza due variabili con le quali determina a quale parte dell'array di caratteri originale appartiene. ... Quando viene creata una sottostringa, l'array di caratteri non viene copiato in un nuovo oggetto String. Entrambi gli oggetti memorizzano invece un riferimento allo stesso array di caratteri. Ma! Il secondo oggetto memorizza altre due variabili, che contengono quali e quanti caratteri di questo array vengono scritti su di esso. ... Pertanto, se prendi una stringa lunga 10.000 caratteri e ne crei 10.000 sottostringhe di qualsiasi lunghezza, queste "sottostringhe" occuperanno pochissima memoria, perché l'array di caratteri non è duplicato. Le stringhe che dovrebbero occupare molto spazio occuperanno solo un paio di byte.
tutto è scritto chiaramente, anche masticato. Ma, poiché sto cercando di migliorare la mia conoscenza dell'inglese, mi rivolgo spesso alla documentazione ufficiale, e in qualche modo non sono riuscito a trovare conferma di questo fatto... Attribuendo questo alla mia disattenzione, ho comunque guardato il codice sorgente di substring() (grazie a IDEA ti permette di farlo con un clic di un pulsante). 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); } Incuriosito, sono andato oltre: * 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); } dove Arrays.copyOfRange è un metodo nativo che restituisce una copia di un array da char... Codice abbastanza banale, e mi è sembrato ovvio che venga semplicemente creata una nuova riga con un nuovo set di caratteri. oppure non ho tenuto conto di qualcosa... Quindi, non credendo pienamente nelle mie conclusioni, ho deciso di testare in qualche modo questa sottostringa(), basandomi su una frase della lezione:
Pertanto, se si prende una stringa lunga 10.000 caratteri e si creano da essa 10.000 sottostringhe di qualsiasi lunghezza, queste "sottostringhe" occuperanno pochissima memoria...
solo che invece di 10_000 faremo subito 100_000_000, perché perdere tempo in sciocchezze. Ho inserito rapidamente il seguente codice: e questo è quello che è successo: i.e. Ogni volta che crei una nuova sottostringa utilizzando bigString.substring(..), l'array di caratteri viene DUPLICATO. In quale altro modo possiamo spiegare un tale aumento del consumo di memoria? Dopo questo personalmente non ho più avuto dubbi riguardo il funzionamento del metodo 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
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION