Во многих статьях об оптимизации Java особое внимание уделяется оптимизации конкатенации строк. Запоминать его не обязательно, это по сути понимание преимуществ и недостатков неизменяемых классов.
На что следует обратить внимание, так это на оптимизацию, сделанную компилятором для сплайсинга строк.Производительность в простых сценариях может быть сравнима с StringBuilder, но в сложных сценариях все еще есть серьезные проблемы с производительностью. В интернете много путаницы по этому вопросу, если есть ошибки в том, что я сказал, прошу меня поправить.
Версия JDK: оракул java 1.8.0_102
В этой статье используется инструмент декомпиляции jad. Я нашел этот инструмент, когда проверял оптимизацию операций сплайсинга строк в Интернете.Он может одновременно декомпилировать исходный код и байт-код.Его легко использовать для личного тестирования.нажмите на меня, чтобы скачать.
Проблемы с производительностью сращивания строк
Перед оптимизацией каждый раз, когда вы используете «+» для конкатенации, будет генерироваться новая строка. Особенно в сценарии зацикливания и объединения строк потеря производительности чрезвычайно серьезна:
- Пустая трата места: результат каждой конкатенации требует создания нового неизменяемого класса.
- Пустая трата времени: новые созданные неизменяемые классы нужно инициализировать; генерируется много «короткоживущего» мусора, влияющего на молодой сборщик мусора и даже на полный сборщик мусора
так называемая простая сцена
Простые сценарии и сложные сценарии — это мои случайные названия, помогающие понять схему оптимизации компилятора.
Простую сцену можно понимать как завершение сращивания в одном предложении:
int i = 0;
String sentence = “Hello” + “world” + String.valueOf(i) + “\n”;
System.out.println(sentence);
Используйте jad, чтобы увидеть результаты оптимизации:
int i = 0;
String sentence = (new StringBuilder()).append(“Hello”).append(“world”).append(String.valueOf(i)).append(“\n”).toString();
System.out.println(sentence);
Разве не удивительно, что операция объединения String оптимизирована в StringBuilder#append()!
На данный момент можно считать, что производительность пространства и производительность времени простых сценариев были оптимально оптимизированы (только для операций сращивания строк), и кажется, что компилятор выполнил необходимые оптимизации. Вы можете проверить, производительность в простых сценариях может быть сравнима с StringBuilder. Но — и это «но» раньше было чушью — оптимизация компилятора мало помогает в сложных сценариях.
так называемая сложная сцена
Так называемый сложный сценарий можно понимать как «компилятор не уверен (или трудно определить, поэтому он не анализирует), сколько раз нужно объединить строку, прежде чем ее нужно будет преобразовать обратно в строку». Это может быть неточным, но это хорошо, чтобы понять это.
Разберем один из простейших сложных сценариев:
String sentence = “”;
for (int i = 0; i < 10000000; i++) {
sentence += “Hello” + “world” + String.valueOf(i) + “\n”;
}
System.out.println(sentence);
идеальная оптимизация
Конечно, какую бы сцену ни ставили, программисты могут вручную оптимизировать:
- Используйте StringBuilder для завершения объединения в сценариях, чувствительных к производительности.
- Используйте более удобную строку в сценариях, нечувствительных к производительности.
PS: не жалуйтесь, этот дизайн API разумен,Делайте правильные вещи в нужном месте.
Идеальная цель — передать это дело javac и JIT:
- Установите пороговое значение для количества сращиваний и начните оптимизацию, если пороговое значение превышено (для javac существует пороговое значение времени компиляции, а у JIT есть пороговое значение времени выполнения для поэтапной оптимизации).
- При оптимизации сгенерируйте объект StringBuilder перед склейкой, замените операцию склейки на StringBuilder#append(), продолжайте использовать объект и используйте StringBuilder#toString() для «ленивой загрузки» нового объекта String, когда ему «нужна» String объект.
Сложность этой схемы оптимизации заключается в анализе кода: машине сложно понять, когда объект String «необходим», поэтому сложно внедрить код в нужное место, чтобы завершить «ленивую загрузку».
Хотя этого трудно достичь, он все же дает идеальные результаты оптимизации для сравнения с практическими решениями:
String sentence = “”;
StringBuilder sentenceSB = new StringBuilder(sentence);
for (int i = 0; i < 10000000; i++) {
sentenceSB.append(“Hello”).append(“world”).append(String.valueOf(i)).append(“\n”);
}
sentence = sentenceSB.toString();
System.out.println(sentence);
фактическая оптимизация
Используйте jad для просмотра фактических результатов оптимизации:
String sentence = “”;
for (int i = 0; i < 10000000; i++) {
sentence = (new StringBuilder()).append(sentence).append(“Hello”).append(“world”).append(String.valueOf(i)).append(“\n”).toString();
}
System.out.println(sentence);
Видно, что на самом деле оптимизация компилятора может достичь оптимума только в простом сценарии: оптимизируется только одно предложение конкатенации строк. Эта степень оптимизации имеет ограниченное улучшение производительности для вышеуказанных сложных сценариев, и во время цикла все равно будет генерироваться большое количество недолговечного мусора, особенно когда строки склеены до большого размера, пространство и время являются фатальными. .
Благодаря анализу идеального решения мы также можем понять беспомощность оптимизации компилятора: компилятор не может (или с трудом) определить с помощью анализа кода, когда самое последнее время для ленивой загрузки. Зачем? Было бы легче понять, если бы мы представили код в другой форме:
String sentence = “”;
for (int i = 0; i < 10000000; i++) {
sentence = sentence + “Hello” + “world” + String.valueOf(i) + “\n”;
}
System.out.println(sentence);
Глядя на код в строке 3, ссылка на предложение находится в правой части уравнения. Я невооруженным глазом знаю, что это предложение только завершает конкатенацию строк, а как насчет машины? По крайней мере, современные машины трудно судить по коду.
Совмещать искусственный интеллект с оптимизацией компиляции в будущем, даже если оптимизация может быть завершена только с вероятностью 90%, это все равно очень круто.
Суммировать
Я не проводил тестирование производительности по этому вопросу. На самом деле нет необходимости слишком углубляться в это, вместо того, чтобы позволить компилятору завершить оптимизацию непонятным образом, лучше использовать код для оптимизации активно и четко, чтобы код мог быть «само собой разумеющимся». ".
Ну а если вам нужна оптимизация, используйте StringBuilder.
Ссылка на эту статью:Исходный код|Оптимизация операции конкатенации строк "+"?
автор:обезьяна 007
Источник:monkeysayhi.github.io
Эта статья основана наCreative Commons Attribution-ShareAlike 4.0Международное лицензионное соглашение выпущено, его можно перепечатать, вывести или использовать в коммерческих целях, но авторство и ссылка на эту статью должны быть сохранены.