.net string immutability

.net - Inmutabilidad de cadena



string immutability (9)

¿Funciona la inmutabilidad de cadena por instrucción o por cadenas dentro de una instrucción?

Por ejemplo, entiendo que el siguiente código asignará dos cadenas en el montón.

string s = "hello "; s += "world!";

"hola" permanecerá en el montón hasta que se recoja la basura; y s ahora hace referencia a "hola mundo!" en el montón Sin embargo, ¿cuántas cadenas asigna la siguiente línea en el montón ... 1 o 2? Además, ¿hay alguna herramienta / forma de verificar los resultados?

string s = "goodbye " + "cruel world!";


El compilador tiene un tratamiento especial para la concatenación de cadenas, por lo que el segundo ejemplo es solo una cadena. Y "internar" significa que incluso si ejecuta esta línea 20000 veces, todavía hay solo 1 cadena.

Volviendo a probar los resultados ... la manera más fácil (en este caso) es probablemente mirar en el reflector:

.method private hidebysig static void Main() cil managed { .entrypoint .maxstack 1 .locals init ( [0] string s) L_0000: ldstr "goodbye cruel world!" L_0005: stloc.0 L_0006: ldloc.0 L_0007: call void [mscorlib]System.Console::WriteLine(string) L_000c: ret }

Como puede ver ( ldstr ), el compilador ya lo hizo por usted.



Si el compilador es "inteligente", solo será una cadena con "¡adiós mundo cruel!"


En realidad, probablemente 3. una cadena const para "adiós", una cadena const para "mundo cruel", y luego una nueva cadena para el resultado.

Puede averiguarlo con seguridad mirando el código generado. Depende del compilador (y, de hecho, del lenguaje, esto no es obvio), pero puede leer la salida de g ++ usando el indicador -a (creo, consulte la página de manual) para obtener el código intermedio .


No confíes en lo que "sabes" sobre cadenas. Puede consultar el código fuente para la implementación de la cadena. Por ejemplo tu ejemplo:

string s = "goodbye " + "cruel world!";

En java asignaría una sola cadena. Java juega algunos trucos bastante lindos y sería difícil de engañar: ¡nunca optimices hasta que lo necesites!

Actualmente, sin embargo, hasta donde yo sé, usando esto:

String s=""; for(int i=0;i<1000;i++) s+=" ";

para crear una cadena de espacio 1000 todavía tiende a ser extremadamente ineficiente

Agregar en un bucle es bastante malo, pero de lo contrario es probablemente tan eficiente como StringBuilder.


Si no se trata solo de una línea, la concatenación de dos cadenas se puede lograr convirtiendo la primera cadena en un StringBuffer, haciendo la concatenación y devolviendo la cadena resultante.

Crear el StringBuffer usted mismo puede parecer exagerado, pero eso es lo que va a suceder de todos modos.


Si solo vas a hacer una o dos concatenaciones de cadenas, no me preocuparía.

Sin embargo, si tiene muchas concatenaciones o tiene un bucle, entonces definitivamente desea tomar precauciones. En el mundo de Java eso significa que usas StringBuffer insteads de concatenar cadena.


Tenga cuidado aquí, porque el compilador puede realizar optimizaciones muy diferentes cuando los valores de cadena se conocen en tiempo de compilación. Si las cadenas que está utilizando no se conocen hasta el tiempo de ejecución (extraído de un archivo de configuración, base de datos o entrada del usuario) verá IL muy diferente.


Las cadenas literales se internan, esto significa que "hello " no reside en el montón pero en el segmento de datos [ver comentario] del programa (y por lo tanto no es elegible para recolección de basura), lo mismo vale para "world" , como para "hello world" que también puede ser internado, si el compilador es lo suficientemente inteligente.

"goodbye cruel world" será internado ya que la concatenación literal de cadenas es algo tratado por el compilador.

Editar: no estoy seguro acerca de la declaración del segmento de datos, consulte esta pregunta para obtener más información.