¿Cuáles son algunas de las razones por las que una versión de Release se ejecutaría de forma diferente a una versión de Debug?

Tengo un progtwig Visual Studio 2005 C ++ que se ejecuta de manera diferente en el modo de lanzamiento que en el modo de depuración. En el modo de lanzamiento, se produce un locking intermitente (aparente). En modo de depuración, no falla. ¿Cuáles son algunas de las razones por las que una versión de Release funcionaría de forma diferente a una versión de Debug?

También vale la pena mencionar que mi progtwig es bastante complejo y utiliza varias bibliotecas de terceros para el procesamiento de XML, la intermediación de mensajes, etc.

¡Gracias por adelantado!

Sobrevivir a la Versión Release ofrece una buena visión general.

Cosas que he encontrado – la mayoría ya están mencionadas

Inicialización de variable por mucho la más común. En Visual Studio, las comstackciones de depuración inicializan explícitamente la memoria asignada a valores determinados, consulte, por ejemplo, Valores de memoria . Estos valores generalmente son fáciles de detectar, causan un error fuera de límites cuando se usan como índice o una infracción de acceso cuando se usan como punteros. Un booleano no inicializado es cierto, sin embargo, y puede causar errores de memoria no inicializados que pasan desapercibidos durante años.

En las comstackciones de Release, donde la memoria no se inicializa explícitamente, solo mantiene el contenido que tenía antes. Esto conduce a lockings “aleatorios” y “valores divertidos”, pero a menudo a lockings determinísticos que requieren que se ejecute un comando aparentemente no relacionado antes del comando que realmente falla. Esto se debe a que el primer comando “configura” la ubicación de la memoria con valores específicos, y cuando las ubicaciones de memoria se reciclan, el segundo comando las ve como inicializaciones. Eso es más común con las variables de stack no inicializadas que con Heap, pero también me ha pasado a mí.

La inicialización de la memoria bruta también puede ser diferente en una comstackción de lanzamiento, ya sea que inicies desde Visual Studio (depurador adjunto) o desde el explorador. Eso hace que los errores de comstackción de versión “más bonitos” que nunca aparecen bajo el depurador.

Las optimizaciones válidas vienen en segundo lugar en mi exepriencia. El estándar C ++ permite muchas optimizaciones que pueden ser sorprendentes, pero son completamente válidas, por ejemplo, cuando dos punteros alias la misma ubicación de memoria, no se considera el orden de inicialización o múltiples subprocesos modifican las mismas ubicaciones de memoria, y usted espera un cierto orden en el que el subproceso B ve los cambios realizados por el subproceso A. A menudo, el culpable es el comstackdor. ¡No tan rápido, joven yedi! – vea abajo

Las versiones de Timing Release no solo “corren más rápido”, por una variedad de razones (optimizaciones, funciones de registro que proporcionan un punto de sincronización de hilo, código de depuración como afirma no ejecutado, etc.) también el tiempo relativo entre las operaciones cambia drásticamente. El problema más común descubierto por eso son las condiciones de carrera, pero también los lockings y la simple ejecución de “orden diferente” de código de mensaje / temporizador / evento. A pesar de que son problemas de sincronización, pueden ser sorprendentemente estables en las construcciones y plataformas, con reproducciones que “funcionan siempre, excepto en PC 23”.

Bytes de guardia . Las comstackciones de depuración a menudo ponen (más) bytes de protección alrededor de instancias y asignaciones seleccionadas, para proteger contra desbordamientos de índices y, a veces, subdesbordamientos. En los raros casos en que el código se basa en desplazamientos o tamaños, por ejemplo, la serialización de estructuras sin procesar, son diferentes.

Otras diferencias de código Algunas instrucciones, p. Ej. Afirman, no se evalúan en nada en las versiones de lanzamiento. A veces tienen diferentes efectos secundarios. Esto es frecuente con macro trickery, como en el clásico (advertencia: múltiples errores)

#ifdef DEBUG #define Log(x) cout << #x << x << "\n"; #else #define Log(x) #endif if (foo) Log(x) if (bar) Run(); 

Lo cual, en una comstackción de lanzamiento, se evalúa como if (foo && bar) Este tipo de error es muy raro con el código C / C ++ normal y las macros que se escriben correctamente.

Errores del comstackdor Esto realmente nunca sucede. Bueno, lo hace, pero es mejor para la mayor parte de su carrera asumir que no es así. En una década de trabajo con VC6, encontré uno en el que todavía estoy convencido de que este es un error de comstackción no fijo, en comparación con docenas de patrones (tal vez incluso cientos de instancias) con una comprensión insuficiente de las Escrituras (también conocido como el estándar).

En la versión de depuración a menudo las aserciones y / o los símbolos de depuración están habilitados. Esto puede conducir a un diseño de memoria diferente. En caso de un puntero incorrecto, desbordamiento de una matriz o acceso a memoria similar, puede acceder en un caso a una memoria defectuosa (por ejemplo, un puntero de función) y en otro caso a una memoria no crítica (p. Ej., Solo una cadena de documentación está en la papelera)

Las variables que no se inicializan explícitamente se pondrán a cero o no en la comstackción Release.

La comstackción de lanzamiento (con suerte) se ejecutará más rápido que tu comstackción de depuración. Si está utilizando más de un hilo, es posible que vea más entrelazado, o simplemente un hilo que se ejecuta más rápido que los otros, que puede que no haya notado en la comstackción de depuración.

Tuve un problema similar no hace mucho tiempo , que terminó siendo causado por la stack que se trata de manera diferente en las comstackciones de lanzamiento. Otras cosas que pueden diferir:

  • La asignación de memoria se maneja de manera diferente con comstackciones de depuración en el comstackdor de VS (es decir, escribiendo 0xcc sobre la memoria borrada, etc.)
  • Desenrollado de bucles y otras optimizaciones del comstackdor
  • Alightment of puninters

Depende tanto del proveedor del comstackdor como de las bibliotecas que comstack con las banderas DEBUG. Mientras que el código DEBUG nunca debería afectar el código de ejecución (no debería tener efectos secundarios) a veces lo hace.

En particular, las variables pueden inicializarse solo en el modo DEBUG y dejarse sin inicializar en el modo RELEASE. El STL en los comstackdores de Visual Studio son diferentes en los modos DEBUG y RELEASE. La idea es que los iteradores estén completamente controlados en DEPURACIÓN para detectar posibles errores (utilizando iteradores invalidados, por ejemplo, un iterador en un vector se invalida si ocurre una inserción después de recuperar el iterador).

Lo mismo sucede con las bibliotecas de terceros, la primera que se me ocurre es QT4, que terminará tu progtwig con una afirmación si un hilo diferente al que creó el objeto gráfico realiza operaciones de pintura.

Con todos los cambios, el código y la huella de memoria serán diferentes en ambos modos. Un problema de puntero (leer la posición de una pasada al final de una matriz) puede pasar desapercibido si esa posición es legible.

Las afirmaciones están destinadas a matar la aplicación durante DEPURACIÓN y desaparecen de las comstackciones de LIBERACIÓN, por lo que no pensaría en aserciones como su problema. Un puntero deshonesto o acceder a uno pasado el final serían mis primeros sospechosos.

Hace algún tiempo hubo problemas con algunas comstackciones optimizaciones rompiendo código, pero no he leído quejas últimamente. Podría haber un problema de optimización allí, pero este no sería mi primer sospechoso.

Las comstackciones de versiones normalmente se comstackn con la optimización habilitada en el comstackdor, mientras que las comstackciones de depuración generalmente no lo son.

En algunos idiomas o cuando se utilizan muchas bibliotecas diferentes, esto puede causar lockings intermitentes, especialmente cuando el nivel de optimización elegido es muy alto.

Sé que este es el caso con el comstackdor C ++ de gcc, pero no estoy seguro del comstackdor de Microsoft.

http://www.debuginfo.com/tips/userbpntdll.html

Debido al hecho de que se agregan bytes de protección en comstackciones de depuración, es posible que pueda acceder de manera “segura” a la memoria que está fuera de los límites de una matriz (particularmente matrices dinámicas), pero esto causará una violación de acceso en la versión de lanzamiento . Este error puede pasar desapercibido, causando un montón corrupto y posiblemente una violación de acceso en un lugar no relacionado con el error original.

Use PageHeap (o, si tiene Herramientas de depuración instaladas, podría usar gflags) para descubrir errores relacionados con montones corruptos.

http://support.microsoft.com/?id=286470

En mi experiencia, la razón más común parece ser que las configuraciones difieren en más formas que las configuraciones de lanzamiento / comstackción. Por ejemplo, se incluyen diferentes libs, o la comstackción de depuración tiene un tamaño de stack diferente al de la versión de lanzamiento.

Para evitar esto en nuestros proyectos de Visual Studio 2005, utilizamos hojas de propiedades de manera exhaustiva. De esta forma, las configuraciones de liberación y depuración pueden compartir configuraciones comunes.

Esta publicación junto con los enlaces proporcionados es muy útil para corregir errores relacionados. añadiendo a la lista anterior, la diferencia en las convenciones de llamadas también puede llevar a este comportamiento: Falló en la versión de lanzamiento solo con la optimización para mí. Declaré como __stdcall y lo definí como __cdecl (por defecto). [curiosamente esta advertencia no se recogió incluso en advertir nivel 4 MSVC?]