Menú de navegaciónMenú
Categorías

La mejor forma de Aprender Programación online y en español www.campusmvp.es

?id=0f9beee6-ac00-4955-87f2-5b6c8f2e2a36

Todo sobre los archivos .PDB: qué son y por qué se generan siempre al compilar una aplicación .NET

Imagen ornamental

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.

Aunque es un formato propietario de Microsoft, en realidad está documentado de forma abierta en GitHub. Si bien existe una API y SDK específicos para trabajar con estos archivos .pdb en Windows y, además, con .NET Core se introdujo una versión "portable" del formato que sirve para cualquier sistema, en otros sistemas debemos usar herramientas específicas de terceros, como PDBParse u otras más avanzadas como Radare2, que es mucho más potente y no sólo sirve para este tipo de archivos, sino que hace ingeniería inversa casi de cualquier cosa.

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.

Tampoco debemos olvidar que los archivos .pdb que se generan para debug y para release no son iguales.

¿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?

La recomendación sería que no: no desactives su generación. Genéralos siempre y archívalos por versiones, aunque no los distribuyas.

No obstante, si tienes la seguridad de que no los quieres, desactivar su generación es muy sencillo en Visual Studio:

La interfaz de usuario descrita debajo

  1. Cambias a la configuración "Release".
  2. En las propiedades del proyecto vas a la pestaña Debug.
  3. En la parte de abajo pulsas el botón Avanzadas, para abrir el diálogo de propiedades avanzadas.
  4. 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.

Fecha de publicación:
José Manuel Alarcón Fundador de campusMVP, es ingeniero industrial y especialista en consultoría de empresa. Ha escrito diversos libros, habiendo publicado hasta la fecha cientos de artículos sobre informática e ingeniería en publicaciones especializadas. Microsoft lo ha reconocido como MVP (Most Valuable Professional) en desarrollo web desde el año 2004 hasta la actualidad. Puedes seguirlo en Twitter en @jm_alarcon o leer sus blog técnico o personal. Ver todos los posts de José Manuel Alarcón
Archivado en: Herramientas

Boletín campusMVP.es

Solo cosas útiles. Una vez al mes.

🚀 Únete a miles de desarrolladores

DATE DE ALTA

x No me interesa | x Ya soy suscriptor

La mejor formación online para desarrolladores como tú

Comentarios (4) -

Excelente articulo.
Como siempre, gracias por compartir

Responder

Hola!

Como dices, Portable es lo mismo que Full para .Net Core y te permite editar el código y continuar.

Lo que he notado es que a veces, mientras depuras, puedes modificar el código y continuar y otras veces, te obliga a detener la depuración para poder hacer cambios.
¿La pregunta sería, por qué y si se puede evitar?

Un saludo.

Responder

José Manuel Alarcón
José Manuel Alarcón

Hola Joseba:

Pues depende mucho del tipo de cambios que hagas e incluso del tipo de aplicación que estés desarrollando. Por ejemplo, en Blazor Server, solo puedes hacer lo editar y continuar cuando no estás depurando (o sea, arrancas con CTRL+F5 y no con F5 solamente).

En cuanto a los tipos de cambios, hay cosas "gordas" que no te permiten editar y continuar, como renombrar variables, añadir espacios de nombres y muchas cosas más. En la documentación de Microsoft tienes una buena lista:

docs.microsoft.com/.../supported-code-changes-csharp

Espero que te sirva.

Saludos!

Responder

Gracias...
No sé, quizá lo imaginé en mi cabeza, pero me pareció leer algo hace años sobre la recompilación en memoria (algo relacionado con roslyn) y poder hacer "cualquier cambio en caliente y recompilar en memoria para seguir).

Las nebulosas mentales :)

Responder

Agregar comentario

Los datos anteriores se utilizarán exclusivamente para permitirte hacer el comentario y, si lo seleccionas, notificarte de nuevos comentarios en este artículo, pero no se procesarán ni se utilizarán para ningún otro propósito. Lee nuestra política de privacidad.