StringBuilder - Reset или создать новый
У меня есть условие, что StringBuilder сохраняет строки, соответствующие шаблону, из большого плоского файла (100 МБ). Однако после достижения условия я пишу содержимое varialble StringBuilder в текстовый файл.
Теперь я задаюсь вопросом, следует ли использовать ту же переменную, сбросив объект →
stringBuilder.delete(0,stringBuilder.length())
ИЛИ
stringBuilder=new StringBuilder();
Просьба предложить, какой из них, по вашему мнению, лучше, насколько это касается проблем производительности и OOM.
Ответы
Ответ 1
Я думаю, что StringBuilder#delete(start, end)
по-прежнему дорогой звонок, вы должны сделать:
stringBuilder.setLength(0);
до reset it.
ОБНОВЛЕНИЕ: После просмотра исходного кода StringBuilder
Кажется, t23 > оставляет старый буфер неповрежденным, и лучше вызвать: 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
Ответ 2
Imho, я бы предложил использовать новое:
stringBuilder = new StringBuilder();
Я никогда не слышал об утечке памяти в StringBuilder, но когда вы действительно нажимаете ограничения, которые вы никогда не знаете. Я бы хеджировал свои ставки против него, каждый раз используя новый экземпляр.
В худшем случае, возможно, вы потеряете некоторую эффективность, и gc получает тренировку, но вы исключаете возможность OOM.
Из-за этого, а также по соображениям я бы лично принял новый подход.
Ответ 3
Одно фундаментальное различие заключается в том, что sb.delete сохраняет ссылку, а конструктор теряет ее.
Если ваш SB является аргументом метода и должен использоваться для передачи контента обратно вызывающему, вы должны использовать sb.delete. Вызывающий имеет исходную ссылку.
Ответ 4
Ну, там большая разница между ними. Первый сохраняет все возможности, которые он имел до того, как вы удалили символы (т.е. stringBuilder.capacity()
), тогда как второй создает новый StringBuilder
с мощностью по умолчанию 16. Конечно, вы можете просто передать stringBuilder.capacity()
в качестве аргумента конструктору, но, тем не менее, важно понимать различие здесь.
В любом случае, я очень сомневаюсь, что вы увидите существенную разницу в производительности между этими двумя вариантами, поэтому выберите то, что более читаемо и проще в управлении. Только когда вы окончательно определили, что это вызывает какое-то узкое место, если вы измените свой подход.
Ответ 5
Я бы использовал:
stringBuilder = new StringBuilder();
потому что, если вы заполняете его большим количеством данных, вызов stringBuilder.setLength(0);
не освободит массив подстановки, поэтому вы можете видеть, что использование памяти остается неоправданным.
Кроме того, это проще читать и понимать.
Ответ 6
В идеале мы должны использовать 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 записывается в том случае, если вы используете ссылку на этот объект, а затем новый должен будет снова установить его
Ответ 7
Если вы находитесь в жестком цикле, и вы продолжите работу в этом цикле после того, как вы напишете данные в файл, вы должны обязательно повторно использовать StringBuilder. Там нет причин не делать этого, и это лучше, чем взбалтывать GC. Если вы пишете это на C или С++, вы повторно используете буфер.
Кроме того, хотя true, что метод delete (...) вызывает System.arraycopy, количество копируемых байтов равно 0, поэтому оно незначительно.
Ah - кто-то еще сказал мне, что существует метод setLength (...), который является самым быстрым способом повторного использования буфера.
Ответ 8
Более дешевое повторное использование созданного объекта, чем выделение нового, всегда. Это также позволяет избежать дополнительной работы для сборщика мусора, поскольку вы обрабатываете только объект.
Более быстрый способ:
stringBuilder.setLength(0);