воскресенье, 13 ноября 2011 г.

Java String.substring() и расход памяти


Недавно в треде на Хабре (http://habrahabr.ru/blogs/java/132500) было обсуждение того, насколько накладен метод String.substring. Мол, каждый раз при вызове этого метода создается новый объект, это жеж кошмар и все такое. Однако, давайте посмотрим чуть внимательнее.

Любой Java-программист знает, как устроен внутри метод String (до определенных пределов :) - никто не знает всех деталей этого процесса, и то, насколько много вы знаете о строках в Java, и определяет вашу зрелость как Java-программиста, ха!).

Итак, у объекта класса String есть три поля. Offset, length, value. Последнее хранит массив символов, которые и представляют из себя строку, первый и второй - смещение от начала строки в массиве value[],  и длину региона в этом массиве, которые и позволяют нам "вырезать" из массива символов value[]  то, что можно назвать "срез текущей строки". Зачем мы храним в памяти эти два дополнительных свойства, смещение и длину строки? По разным причинам, одна из них - следование паттерну Flightweight, который позволяет нам использовать тот факт, что массив value[] - неизменяем, и расшаривать один общий экземпляр этого массива при вызове методов, которые возвращают нам часть исходной строки, например, substring.

Посмотрим внимательнее на метод String.substring:


public String substring(int beginIndex, int endIndex) {

 if (beginIndex < 0) {

 throw new StringIndexOutOfBoundsException(beginIndex);

 }

 if (endIndex > count) {

 throw new StringIndexOutOfBoundsException(endIndex);

 }

 if (beginIndex > endIndex) {

 throw new StringIndexOutOfBoundsException(endIndex - beginIndex);

 }

 return ((beginIndex == 0) && (endIndex == count)) ? this :

 new String(offset + beginIndex, endIndex - beginIndex, value);

 }



Смотрим теперь по коду конструктор с такой же сигнатурой, видим:

// Package private constructor which shares value array for speed.

 String(int offset, int count, char value[]) {

 this.value = value;

 this.offset = offset;

 this.count = count;

 }

Вывод — при вызове метода Substring, новый объект String конечно создается, но массив символов, используемый для хранения данных, не копируется. В новом объекте String будут просто использованы другие значения для offset/lenght, и ссылка на тот же самый массив символов, относительно которых эти offset/length и берутся.


Небольшая тонкость относительно копирования строк, о которой не все знают. Иногда об этом не знают даже те, кто пишет об оптимизации использования памяти на Хабре ;)

5 комментариев:

  1. Да, про него я забыл упомянуть. Спасибо за напоминание!

    ОтветитьУдалить
  2. Дык, в той статье говорится о ситуации, когда мы прочитали длинную-предлинную строку, а работаем с небольшим кусочком этой строки. В такой ситуации был как раз таки выгодно скопировать маленький кусочек массива, чтобы большой массив был убран сборщиком мусора. И чтобы это произошло дядечка с хабрахабра предлагает делать

    ss = new String(longString.substring(3))

    вместо


    ss = longString.substring(3)

    Так мы заставляем создать новый маленький массив символов, чтобы старый был убран gc.


    Так что слив не засчитан:)

    ОтветитьУдалить
  3. P.S.

    А вообще, лучше использовать apache-commons StringUtils - там гораздо оптимальней ф-ии написаны, чем в стандартном классе.

    Стандартный split, кстати, вообще редко когда стоит использовать: внутри этой ф-ии при каждом вызове компилится регексп. Это ужос!

    ОтветитьУдалить
  4. In 2012, there was a push for south Jersey to permit gamblers to use mobile units to gamble in casinos, pushed by Senator Jim Whelan, to compete with Las Vegas. At the time, mobile gaming units have been already adopted in Las Vegas in casinos, permitting casinos to increase gaming floor to their outer premises. In 2012, the New Jersey Legislature permitted "the usage of} hand-held playing units at Atlantic City casinos," and was waiting on the Governor's signature to pass. The new law requires any casino that gives mobile sports activities wagering, and each mobile sports activities wagering platform 메리트카지노 provider, to submit an in depth annual report to to} the Commission. The greatest online playing websites permit gamers to guess on sports activities and casino video games corresponding to blackjack and slots.

    ОтветитьУдалить