В вопросе C ++ об оптимизации и стиле кода в нескольких ответах упоминается «SSO» в контексте оптимизации копий std::string
. Что SSO означает в этом контексте?
Ясно, что не «единый вход». «Оптимизация общей строки», возможно?
c++
string
optimization
Raedwald
источник
источник
std::string
реализовано», а другой спрашивает «что означает SSO», вы должны быть абсолютно безумны, чтобы считать их одним и тем же вопросомОтветы:
Фон / Обзор
Операции с автоматическими переменными («из стека», которые являются переменными, которые вы создаете без вызова
malloc
/new
), как правило, выполняются намного быстрее, чем операции с бесплатным хранилищем («куча», которые являются переменными, которые создаются с использованиемnew
). Однако размер автоматических массивов фиксируется во время компиляции, а размер массивов из бесплатного хранилища - нет. Кроме того, размер стека ограничен (обычно несколько мегабайт), тогда как свободное хранилище ограничено только памятью вашей системы.SSO - это оптимизация коротких / маленьких строк. A
std::string
обычно хранит строку как указатель на свободное хранилище («куча»), которое дает характеристики производительности, аналогичные тем, которые вы вызываетеnew char [size]
. Это предотвращает переполнение стека для очень больших строк, но это может быть медленнее, особенно при операциях копирования. В качестве оптимизации многие реализацииstd::string
создают небольшой автоматический массив, что-то вродеchar [20]
. Если у вас есть строка длиной не более 20 символов (в данном примере фактический размер меняется), она будет сохранена непосредственно в этом массиве. Это избавляет от необходимостиnew
вообще звонить , что немного ускоряет процесс.РЕДАКТИРОВАТЬ:
Я не ожидал, что этот ответ будет настолько популярен, но, поскольку он есть, позвольте мне дать более реалистичную реализацию с оговоркой, что я никогда не читал ни одной реализации SSO «в дикой природе».
Детали реализации
Как минимум,
std::string
необходимо хранить следующую информацию:Размер может быть сохранен как
std::string::size_type
или как указатель на конец. Разница лишь в том, хотите ли вы вычесть два указателя при вызове пользователяsize
или добавитьsize_type
к указателю при вызове пользователяend
. Емкость может быть сохранена в любом случае.Вы не платите за то, что не используете.
Сначала рассмотрим наивную реализацию, основанную на том, что я изложил выше:
Для 64-битной системы это обычно означает, что в
std::string
каждой строке содержится 24 байта служебных данных плюс еще 16 для буфера SSO (здесь выбрано 16 вместо 20 из-за требований заполнения). На самом деле не имеет смысла хранить эти три элемента данных плюс локальный массив символов, как в моем упрощенном примере. Еслиm_size <= 16
, тогда я добавлю все данныеm_sso
, так что я уже знаю емкость и мне не нужен указатель на данные. Еслиm_size > 16
, тогда мне не нужноm_sso
. Там нет абсолютно никаких совпадений, где мне все они нужны. Разумное решение, которое не тратит впустую пространство, выглядело бы как-то так (непроверено, только для примера):Я бы предположил, что большинство реализаций выглядят больше так.
источник
std::string const &
, получение данных является одной косвенной памятью, поскольку данные хранятся в местоположении ссылки. Если бы не было небольшой оптимизации строки, для доступа к данным потребовалось бы две косвенные зависимости памяти (сначала для загрузки ссылки на строку и чтения ее содержимого, а затем для чтения содержимого указателя данных в строке).SSO - это сокращение от «Оптимизация малых строк», метод, при котором небольшие строки внедряются в тело класса строк, а не в отдельный буфер.
источник
Как уже объяснялось в других ответах, SSO означает оптимизацию малых / коротких строк . Мотивация этой оптимизации является неопровержимым доказательством того, что приложения в целом обрабатывают намного более короткие строки, чем более длинные строки.
Как объяснил Дэвид Стоун в своем ответе выше ,
std::string
класс использует внутренний буфер для хранения содержимого до заданной длины, что исключает необходимость динамического выделения памяти. Это делает код более эффективным и быстрым .Этот другой связанный ответ ясно показывает, что размер внутреннего буфера зависит от
std::string
реализации, которая варьируется от платформы к платформе (см. Результаты тестов ниже).Ориентиры
Вот небольшая программа, которая тестирует операцию копирования множества строк одинаковой длины. Он начинает печатать время для копирования 10 миллионов строк с длиной = 1. Затем он повторяется со строками длины = 2. Он продолжает работать, пока длина не станет 50.
Если вы хотите запустить эту программу, вы должны сделать это
./a.out > /dev/null
так, чтобы время печати строк не учитывалось. Цифры, которые имеют значение, печатаютсяstderr
, поэтому они будут отображаться в консоли.Я создал диаграммы с выводом из моих машин MacBook и Ubuntu. Обратите внимание, что существует огромный скачок во времени для копирования строк, когда длина достигает заданной точки. Это тот момент, когда строки больше не помещаются во внутренний буфер, и необходимо использовать выделение памяти.
Также обратите внимание, что на машине linux переход происходит, когда длина строки достигает 16. В macbook переход происходит, когда длина достигает 23. Это подтверждает, что SSO зависит от реализации платформы.
Ubuntu
MacBook Pro
источник