StringBuilder - сброс или создание нового

17

У меня есть условие, что StringBuilder сохраняет строки, соответствующие шаблону, из большого плоского файла (100 МБ). Однако после достижения условия я пишу содержимое varialble StringBuilder в текстовый файл.

Теперь я задаюсь вопросом, следует ли мне использовать одну и ту же переменную, сбросив объект - & gt;

stringBuilder.delete(0,stringBuilder.length())

ИЛИ

stringBuilder=new StringBuilder();

Просьба предложить, какой из них, по вашему мнению, лучше, насколько это касается проблем производительности и OOM.

    
задан Chandru 12.09.2013 в 16:18
источник

8 ответов

28

Я думаю, что StringBuilder#delete(start, end) по-прежнему дорогой вызов, вы должны сделать:

stringBuilder.setLength(0);

, чтобы сбросить его.

ОБНОВЛЕНИЕ: После просмотра исходный код StringBuilder Кажется, что setLength(int) оставляет старый буфер неповрежденным, и лучше позвонить: StringBuilder#trimToSize() после вызова выше, attempts to reduce storage used for the character sequence .

Итак, что-то вроде этого было бы более эффективным:

stringBuilder.setLength(0); // set length of buffer to 0
stringBuilder.trimToSize(); // trim the underlying buffer
    
ответ дан anubhava 12.09.2013 в 16:22
источник
5

Imho, я бы предложил использовать новое:

stringBuilder = new StringBuilder();

Я никогда не слышал об утечке памяти в StringBuilder, но когда вы действительно нажимаете ограничения, которые вы никогда не знаете. Я бы хеджировал свои ставки против него, каждый раз используя новый экземпляр.

В худшем случае, возможно, вы потеряете некоторую эффективность, и gc получает тренировку, но вы исключаете возможность OOM.

Из-за этого, а также по соображениям я бы лично принял новый подход.

    
ответ дан vikingsteve 12.09.2013 в 16:27
источник
4

Одно фундаментальное различие заключается в том, что sb.delete сохраняет ссылку, а конструктор теряет ее.

Если ваш SB является аргументом метода и должен использоваться для передачи содержимого обратно вызывающему, вы должны использовать sb.delete. Вызывающий имеет исходную ссылку.

    
ответ дан user3241961 27.01.2014 в 21:02
источник
2

Хорошо, есть большая разница между ними. Первый сохраняет все возможности, которые были у него до того, как вы удалили символы (т. Е.% Co_de%), тогда как второй создает новый stringBuilder.capacity() с мощностью по умолчанию, 16. Конечно, вы можете просто передать StringBuilder в качестве аргумента конструктору, но важно понять различие здесь, тем не менее.

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

    
ответ дан arshajii 12.09.2013 в 16:24
источник
1

Я бы использовал:

 stringBuilder = new StringBuilder();

, потому что, если вы заполняете его большим количеством данных, вызов stringBuilder.setLength(0); не освободит массив подстановки, поэтому вы можете видеть, что использование памяти остается неоправданным.

Кроме того, это проще читать и понимать.

    
ответ дан Bohemian 12.09.2013 в 16:30
источник
1

В идеале мы должны использовать new StringBuilder() Копаем немного в классе StringBuilder из grepcode Я узнаю следующее.

Создание нового объекта:

/**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

new StringBuilder () создает новый объект с начальным массивом char. Накладные расходы здесь: GC будет вызван для очистки старого объекта.

Использование delete:

public AbstractStringBuilder delete(int start, int end) {
        if (start < 0)
            throw new StringIndexOutOfBoundsException(start);
        if (end > count)
            end = count;
        if (start > end)
            throw new StringIndexOutOfBoundsException();
        int len = end - start;
        if (len > 0) {
            System.arraycopy(value, start+len, value, start, count-end);
            count -= len;
        }
        return this;
    }

Использование Length и TrimToSize:

public void trimToSize() {
        if (count < value.length) {
            value = Arrays.copyOf(value, count);
        }
    }

Вызов copyOf из класса массива

public static char [] copyOf (char [] original, int newLength) {     char [] copy = new char [newLength];     System.arraycopy (оригинал, 0, копия, 0,                      Math.min (original.length, newLength));     возвратная копия; }

Теперь он также вызовет System.arrayCopy , который является родным методом. Теперь, если вы видите в copyOf, мы создаем новый charArray снова длиной 0, и когда мы попытаемся добавить к нему лишние данные, он будет вызывать расширение , потому что текущая длина будет 0 . Поэтому я думаю, что лучше назвать новый StringBuilder ()

Вы можете увидеть приведенный выше код на grepcode

PS: @ user3241961 записывается в том случае, если вы используете ссылку на этот объект, а затем новый должен будет снова установить его

    
ответ дан Akhil Dad 29.07.2015 в 15:11
источник
0

Если вы находитесь в жестком цикле, и вы продолжите работу в этом цикле после того, как вы напишете данные в файл, вы должны обязательно повторно использовать StringBuilder. Нет причин не делать этого, и это лучше, чем вспенивание GC. Если вы пишете это на C или C ++, вы повторно используете буфер.

Кроме того, хотя true, что метод delete (...) вызывает System.arraycopy, количество копируемых байтов равно 0, поэтому оно незначительно.

Ah - кто-то еще сказал мне, что существует метод setLength (...), который является самым быстрым способом повторного использования буфера.

    
ответ дан jpayne 12.09.2013 в 16:37
источник
0

Более дешевое повторное использование созданного объекта, чем выделение нового, всегда. Это также позволяет избежать дополнительной работы для сборщика мусора, поскольку вы обрабатываете только объект.

Более быстрый способ:

stringBuilder.setLength(0);
    
ответ дан jmlotero 30.03.2017 в 09:51
источник