En una pregunta de C ++ sobre optimización y estilo de código , varias respuestas se referían a "SSO" en el contexto de la optimización de copias de std::string
. ¿Qué significa SSO en ese contexto?
Claramente no es "inicio de sesión único". ¿"Optimización de cadena compartida", tal vez?
c++
string
optimization
Raedwald
fuente
fuente
std::string
implementa", y otra pregunta: "¿Qué SSO media", que tiene que ser absolutamente loco para considerarlos a ser la misma preguntaRespuestas:
Antecedentes / Resumen
Las operaciones en variables automáticas ("de la pila", que son variables que crea sin llamar
malloc
/new
) son generalmente mucho más rápidas que las que involucran la tienda libre ("el montón", que son variables que se crean usandonew
). Sin embargo, el tamaño de las matrices automáticas se fija en el momento de la compilación, pero el tamaño de las matrices de la tienda gratuita no lo es. Además, el tamaño de la pila es limitado (generalmente unos pocos MiB), mientras que la tienda gratuita solo está limitada por la memoria de su sistema.SSO es la optimización de cadenas cortas / pequeñas. A
std::string
generalmente almacena la cadena como un puntero a la tienda libre ("el montón"), que proporciona características de rendimiento similares a las de llamarnew char [size]
. Esto evita un desbordamiento de la pila para cadenas muy grandes, pero puede ser más lento, especialmente con operaciones de copia. Como optimización, muchas implementaciones destd::string
crear una pequeña matriz automática, algo asíchar [20]
. Si tiene una cadena de 20 caracteres o menos (dado este ejemplo, el tamaño real varía), la almacena directamente en esa matriz. Esto evita la necesidad de llamarnew
, lo que acelera un poco las cosas.EDITAR:
No esperaba que esta respuesta fuera tan popular, pero dado que lo es, permítanme dar una implementación más realista, con la advertencia de que nunca he leído ninguna implementación de SSO "en la naturaleza".
Detalles de implementacion
Como mínimo, a
std::string
necesita almacenar la siguiente información:El tamaño podría almacenarse como un
std::string::size_type
o como un puntero al final. La única diferencia es si desea restar dos punteros cuando el usuario llamasize
o agregarsize_type
un puntero cuando el usuario llamaend
. La capacidad se puede almacenar de cualquier manera también.No pagas por lo que no usas.
Primero, considere la implementación ingenua basada en lo que describí anteriormente:
Para un sistema de 64 bits, eso generalmente significa que
std::string
tiene 24 bytes de 'sobrecarga' por cadena, más otros 16 para el búfer SSO (16 elegidos aquí en lugar de 20 debido a los requisitos de relleno). Realmente no tendría sentido almacenar esos tres miembros de datos más una matriz local de caracteres, como en mi ejemplo simplificado. Sim_size <= 16
, entonces pondré todos los datosm_sso
, así que ya sé la capacidad y no necesito el puntero a los datos. Sim_size > 16
, entonces no lo necesitom_sso
. No hay absolutamente ninguna superposición donde los necesito a todos. Una solución más inteligente que no desperdicia espacio se vería algo más como esto (no probado, solo con fines de ejemplo):Supongo que la mayoría de las implementaciones se parecen más a esto.
fuente
std::string const &
, obtener los datos es una indirecta de memoria única, porque los datos se almacenan en la ubicación de la referencia. Si no hubiera una optimización de cadena pequeña, el acceso a los datos requeriría dos indirecciones de memoria (primero para cargar la referencia a la cadena y leer su contenido, luego la segunda para leer el contenido del puntero de datos en la cadena).SSO es la abreviatura de "Small String Optimization", una técnica en la que las pequeñas cadenas están incrustadas en el cuerpo de la clase de cadena en lugar de utilizar un búfer asignado por separado.
fuente
Como ya se explicó en las otras respuestas, SSO significa optimización de cadena pequeña / corta . La motivación detrás de esta optimización es la evidencia innegable de que las aplicaciones en general manejan cadenas mucho más cortas que cadenas más largas.
Como explicó David Stone en su respuesta anterior , la
std::string
clase usa un búfer interno para almacenar contenidos de una longitud determinada, y esto elimina la necesidad de asignar memoria de forma dinámica. Esto hace que el código sea más eficiente y rápido .Esta otra respuesta relacionada muestra claramente que el tamaño del búfer interno depende de la
std::string
implementación, que varía de una plataforma a otra (ver los resultados de referencia a continuación).Puntos de referencia
Aquí hay un pequeño programa que compara la operación de copia de muchas cadenas con la misma longitud. Comienza a imprimir el tiempo para copiar 10 millones de cadenas con longitud = 1. Luego se repite con cadenas de longitud = 2. Continúa hasta que la longitud sea 50.
Si desea ejecutar este programa, debe hacerlo de
./a.out > /dev/null
manera que no se cuente el tiempo para imprimir las cadenas. Los números que importan se imprimen enstderr
que aparezcan en la consola.He creado gráficos con la salida de mis máquinas MacBook y Ubuntu. Tenga en cuenta que hay un gran salto en el tiempo para copiar las cadenas cuando la longitud alcanza un punto determinado. Ese es el momento en que las cadenas ya no caben en el búfer interno y se debe utilizar la asignación de memoria.
Tenga en cuenta también que en la máquina Linux, el salto ocurre cuando la longitud de la cadena alcanza 16. En el macbook, el salto ocurre cuando la longitud alcanza 23. Esto confirma que SSO depende de la implementación de la plataforma.
Ubuntu
Macbook Pro
fuente