Performance: String o StringBuilder

 

Bueno, antes de la etapa de refactorización, y para ver como podemos enfocarla, toca profiling de mi parte del proyecto.


Primero, y lo importante, es buscar un buen profiler para comprar la licencia, así que empezamos tirando de trials. Aquí lo poco que he probado.



  • RedGate Ants Profiler (595$): Ya lo había probado en otros proyectos, y me gusta mucho. Es intuitivo y con una presentación de resultados muy fácil de interpretar. Aquí le podéis echar un vistazo: http://www.red-gate.com/products/ANTS_Profiler/index.htm

  • JetBrains DotTrace (499$): No lo conocía, y no me ha gustado mucho, quizás porque lo comparaba con Ants. Es algo más barato que Ants, aunque Ants incluye software para test de aplicaciones y servicios web muy completo, mucho más que el de DotTrace.

  • CLR Profiler: Profiler gratuíto que nos regala Microsoft. Como su propio nombre indica, exclusivamente hace profiling del CLR, aunque casualmente, y para el caso que me ocupaba, me resolvió unas cuantas dudas.

 


Expongo mi caso:


Mantengo en memoria de mi aplicación una lista de strings bastante seria (en las que cargo urls para generar ficheros .asx -listas de reproducción para wmp-). Además mantengo otras listas de strings similares, y al hacer el profiling, veo que la mayoría de la memoria está ocupada por strings. Eso ya lo suponía, por lo que decido cambiar esos strings por objetos  de la clase StringBuilder, para analizar la diferencia de comportamiento. Una vez hecho esto, vuelvo a realizar un profiling, esperando haber mejorado algo, y pum!!, sorpresa: el rendimiento empeora por mucho.



 


Pero aún más asombrado me encuentro cuando veo el histograma de vida de los objetos por edad (fijarse en las estadísticas de recolección de basura)



 


Además de dar a entender que mi manejo del Paint es  vergonzoso, se observa una sobrecarga de instancias de la clase String (en rojo) mucho mayor, cuando en varios artículos indicaba lo contrario.


¿Entonces, qué está pasando aquí? El problema es inherente a la arquitectura de la clase String y la clase StringBuilder. Un StringBuilder contiene un buffer, de forma que siempre que necesitemos aumentar memoria, para realizar cualquier operación (concatenación, reemplazo, etc…), lo que se aumenta es el buffer del StringBuilder. Sin embargo, un String se comporta de otra forma; cuando necesita ampliar la memoria que necesita, crea una nueva instancia del mismo del tamaño adecuado. Recordemos que al CLR una de las operaciones que más le cuesta es crear instancias de las clases, lo que hace que el rendimiento de la aplicación decayese en caso de utilizar una gran carga de Strings (esto no es correcto del todo, ahora llegamos al kit de la cuestión).


Entonces, si esto es así, ¿porqué demonios he perdido rendimiento utilizando StringBuilders? Como suele pasar, todo es relativo, y a la hora de decantarse por un String o por un StringBuilder, debemos analizar QUÉ vamos a hacer con él. En mi caso, creo los objetos, les asigno un valor y luego utilizo ese valor. Al hacerlo con un StringBuilder, la instancia es más pesada (recordemos el buffer que lleva) y eso hace que el tamaño de memoria commited aumenten tanto; si durante la ejecución realizase operaciones con la instancia que obligasen a modificar su tamaño (concatenaciones, eliminaciones, reemplazos, etc…), estaría utilizando la ventaja que aporta el StringBuilder, pero como en mi caso no realizo prácticamente ninguna operación de esas, en lugar de resultar ventajoso, me ocasiona una sobrecarga de memoria que hace decaer el rendimiento de la aplicación.


 


Quería compartir con vosotros esto, porque seguro que se me escapan mil cosas, pero también sé que muchísima gente no le da importancia a este tema, y como decía el anuncio de la DGT, “las imprudencias se pagan carísimas” :D.


 


¡¡Saludos!!

3 comentarios en “Performance: String o StringBuilder”

  1. Un pequeño dato… Realmente los Strings son inmutables, una vez asignas un String, si lo cambias, realmente como mínimo se crea un nuevo String. Eso quiere decir que cada vez que cambies un string, se crea una instancia, aunque pudiese caber lo “nuevo” en la memoria del “viejo”.

    Obviamente en el caso que comentas, que les asignas un valor y no lo modificas, el uso de String es perfectamente válido. Pero para modificaciones, en cuanto sobrepases un umbral bastante bajo, el uso de StringBuilders es más que recomendable.

  2. Buena puntualización Augusto. Había querido entender que se creaba una nueva nstancia de la clase String sólo cuando se cambiaba su tamaño. Bueno, más razón que hay que darle al profiler 😉

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *