04/01/2021Artículo original
Cuando trabajas con .NET habrás observado que, al compilar una aplicación, aparte del .exe o .dll correspondientes se generan también unos archivos con la extensión .pdb. Estos tienen el mismo nombre que el ensamblado principal, pero no parecen hacer nada.
PDB es el acrónimo de Program Database. Es un formato propietario de Microsoft que almacena información de depuración de las aplicaciones ejecutables en Windows (.exe y .dll). Se crea a partir del código fuente para obtener una relación exhaustiva de los símbolos (variables, objetos, métodos…) del programa y su ubicación en el código y relacionarlos con el código compilado resultante. De esta manera, si necesitamos depurar la aplicación, las interfaces de depuración pueden “casar” las instrucciones de bajo nivel que se están ejecutando con las líneas de código concretas con las que se corresponden.
Con un PDB puedes depurar el código fuente a partir de volcados de memoria (y/o el ejecutable) con Visual Studio y herramientas como WinDBG.
Archivos PDB en release
Pero, si los archivos .pdb son para depuración, ¿por qué cuando genero una aplicación en modo release, para producción, también se me generan archivos .pdb? ¿Para qué me sirve eso?
El motivo parece obvio, pero no lo es tanto. Y es que, si no tuviésemos este tipo de archivos, no podríamos depurar la aplicación en producción.
¿Cómo? ¿Depurar en producción? Parece un contrasentido. Al fin y al cabo, ya depuramos la aplicación mientras estamos desarrollándola ¿no?
En efecto. Durante las pruebas y el desarrollo ya depuramos la aplicación, por lo que la podemos desplegar a producción con ciertas garantías. Sin embargo, debemos tener en cuenta varias cosas:
- Hay muchas cosas que se nos van a escapar durante el desarrollo, que pueden producir errores una vez la aplicación está en funcionamiento.
- En ciertos tipos de aplicaciones, al estar en producción y tener muchos usuarios simultáneos, se dan situaciones muy difíciles de reproducir en desarrollo o pruebas, especialmente las que tienen que ver con código multisubproceso/asincronía.
- Si la aplicación se distribuye a muchos usuarios finales es muy probable que ciertos entornos personalizados (configuración, sistema operativo, nivel de parche, drivers…) den problemas que no hayamos podido tener en cuenta durante el desarrollo. En ese caso necesitaremos el .pdb para depurar el ejecutable concreto que presente los problemas.
- Cuando compilamos para release se le aplican multitud de optimizaciones al código final que no están al compilar en debug (no tanto por el switch/debug como el /optimize que se aplica en este caso). Generalmente esto no tiene impacto alguno sobre el funcionamiento de la aplicación más allá de mejorar su rendimiento, pero en ciertas ocasiones sí que pueden introducir cambios sutiles que afecten al resultado final e introduzcan nuevos bugs.
- Si hacemos profiling y optimización del ejecutable final, necesitaremos el .pdb para localizar las líneas que se pueden optimizar.
Regenerar archivos .pdb
Vale. Me has convencido. Son útiles. Pero, dado que tengo el código fuente de cada versión gracias al control de código fuente con Git, si me hace falta puedo volver a compilarlo y generar el PDB si lo necesito ¿no?
Pues sí, pero no… La lógica es aplastante, y será cierto en la mayoría de los casos. Pero hay un problema: nadie te garantiza que el mismo código exacto, unos meses después, genere el mismo archivo .pdb que se generó cuando compilaste la primera vez.
El motivo es que si cambia la versión del compilador o incluso de Visual Studio, el ejecutable generado puede ser diferente, y por lo tanto el PDB también. No sólo eso, incluso el mismo compilador no siempre genera el mismo código ejecutable todas las veces, según asegura Eric Lippert, exmiembro del equipo de diseño del lenguaje C# en Microsoft.
¿Debería incluir los .pdb cuando distribuya mi aplicación a los usuarios?
No es necesario que lo hagas. Ocupan bastante y en la mayoría de los casos no los vas a usar para nada. Por eso, los puedes quitar del paquete final que distribuyas (instalación, ZIP…) y obviar dárselos a los usuarios finales.
Si luego los necesitas siempre puedes facilitárselos y depurar in situ. Por eso es interesante que los archives en algún lado para tenerlos a mano, solo, por si acaso.
Desactivar la generación de archivos PDB en release
De acuerdo otra vez. Siempre me convences… Pero, de todos modos, seamos realistas, yo no voy a depurar mi aplicación en producción nunca. ¿No sería mejor directamente no generarlos?
No obstante, si tienes la seguridad de que no los quieres, desactivar su generación es muy sencillo en Visual Studio:
- Cambias a la configuración “Release”.
- En las propiedades del proyecto vas a la pestaña Debug.
- En la parte de abajo pulsas el botón Avanzadas, para abrir el diálogo de propiedades avanzadas.
- En la lista desplegable para Información de depuración escoges la opción None.
Esto desactivará la generación de símbolos de depuración, por lo que prueba conseguida. Pero te recomiendo que no lo hagas.
Fíjate en que hay varias opciones y por defecto, en .NET Core / .NET 5 la elegida es Portable. Lo que significan estas opciones es:
- None: no se generan símbolos de depuración.
- db-only: podrás depurar el código a partir de volcados de memoria, pero sin poder usar el ejecutable.
- Full: igual que el anterior pero además podrás adjuntar el ejecutable al depurador ya que incluirá dentro de éste cierta metainformación de depuración. Te permite hacer cosas como “Editar y continuar” en Visual Studio, que están muy bien.
- Portable: un formato nuevo de PDB que surgió con .NET Core y que genera un archivo de depuración compatible con todos los sistemas operativos, lo que pega bien con la naturaleza multiplataforma de .NET Core. Es el equivalente “moderno” a la opción Full y es lo que está marcado en el caso de aplicaciones .NET Core/.NET 5+.
- Embedded: embebe la información de depuración directamente en el ensamblado final, por lo que no se genera ningún archivo .pdb. Ahora bien, siempre estarás distribuyendo esta información y el .exe o .dll ocuparán mucho más.
Espero que este repaso a los PDB haya arrojado luz sobre qué son, cuál es su utilidad y cómo debes gestionarlos.