Programing

릴리스 빌드가 디버그 빌드와 다르게 실행되는 몇 가지 이유는 무엇입니까?

lottogame 2021. 1. 10. 16:46
반응형

릴리스 빌드가 디버그 빌드와 다르게 실행되는 몇 가지 이유는 무엇입니까?


릴리스 모드에서 디버그 모드와 다르게 실행되는 Visual Studio 2005 C ++ 프로그램이 있습니다. 릴리스 모드에서 (명백한) 간헐적 인 충돌이 발생합니다. 디버그 모드에서는 충돌하지 않습니다. 릴리스 빌드가 디버그 빌드와 다르게 작동하는 이유는 무엇입니까?

내 프로그램이 상당히 복잡하고 XML 처리, 메시지 중개 등을 위해 여러 타사 라이브러리를 사용한다는 점도 언급 할 가치가 있습니다.

미리 감사드립니다!


릴리스 버전에서 살아남 으면 좋은 개요가 제공됩니다.

내가 만난 것들-대부분은 이미 언급 됨

변수 초기화 가 가장 일반적입니다. Visual Studio에서 디버그 빌드는 할당 된 메모리를 지정된 값으로 명시 적으로 초기화합니다 (예 : 여기에서 메모리 값 참조). 이러한 값은 일반적으로 쉽게 발견 할 수 있으며 인덱스로 사용하면 범위를 벗어난 오류가 발생하고 포인터로 사용되면 액세스 위반이 발생합니다. 그러나 초기화되지 않은 부울은 참이며, 초기화되지 않은 메모리 버그가 수년 동안 감지되지 않을 수 있습니다.

메모리가 명시 적으로 초기화되지 않은 릴리스 빌드에서는 이전에 있었던 내용 만 유지합니다. 이로 인해 "재미있는 값"및 "무작위"충돌이 발생하지만 실제로 충돌하는 명령 전에 실행되어야하는 명백히 관련없는 명령이 필요한 결정 론적 충돌이 자주 발생합니다. 이는 특정 값으로 메모리 위치를 "설정"하는 첫 번째 명령으로 인해 발생하며 메모리 위치가 재활용 될 때 두 번째 명령은이를 초기화로 간주합니다. 힙보다 초기화되지 않은 스택 변수에서 더 일반적이지만 후자가 나에게도 발생했습니다.

원시 메모리 초기화는 Visual Studio (디버거 연결)에서 시작하는 것과 탐색기에서 시작하는 것과 관계없이 릴리스 빌드에서 다를 수도 있습니다. 이는 디버거 아래에 나타나지 않는 "가장 좋은"종류의 릴리스 빌드 버그를 만듭니다.

유효한 최적화 는 내 실력에서 두 번째입니다. C ++ 표준을 사용하면 놀라 울 수 있지만 전적으로 유효한 많은 최적화를 수행 할 수 있습니다. 예를 들어 두 포인터가 동일한 메모리 위치를 별칭으로 지정하거나 초기화 순서가 고려되지 않거나 여러 스레드가 동일한 메모리 위치를 수정하고 특정 순서를 예상하는 경우 스레드 B는 스레드 A에 의해 변경된 내용을 볼 수 있습니다. 종종 컴파일러는 이러한 변경 사항을 탓합니다. 빠르지 않아, 젊은 예디! -아래 참조

타이밍 릴리스 빌드는 다양한 이유 (최적화, 스레드 동기화 지점을 제공하는 로깅 함수, 실행되지 않은 어설 션과 같은 디버그 코드 등)로 인해 "더 빨리 실행"되는 것이 아니라 작업 간의 상대적 타이밍이 크게 변경됩니다. 이에 의해 발견되는 가장 일반적인 문제는 경합 상태뿐 아니라 교착 상태와 메시지 / 타이머 / 이벤트 기반 코드의 간단한 "다른 순서"실행입니다. 타이밍 문제이기는하지만 "PC 23을 제외하고 항상 작동"하는 재생산으로 빌드와 플랫폼간에 놀라 울 정도로 안정적 있습니다.

가드 바이트 . 디버그 빌드는 종종 선택한 인스턴스 및 할당 주위에 (더 많은) 보호 바이트를 배치하여 인덱스 오버플로 및 때로는 언더 플로로부터 보호합니다. 코드가 오프셋 또는 크기에 의존하는 드문 경우 (예 : 원시 구조 직렬화)는 다릅니다.

기타 코드 차이점 일부 명령어 (예 : 어설 션)는 릴리스 빌드에서 아무것도 평가하지 않습니다. 때때로 그들은 다른 부작용이 있습니다. 이것은 고전에서와 같이 매크로 속임수에서 만연합니다 (경고 : 여러 오류)

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

if (foo)
  Log(x)
if (bar)
  Run();

릴리스 빌드에서 if (foo && bar)로 평가됩니다. 이러한 유형의 오류는 정상적인 C / C ++ 코드와 올바르게 작성된 매크로에서는 매우 드뭅니다.

컴파일러 버그 이것은 실제로 결코 발생하지 않습니다. 글쎄요,하지만 그렇지 않다고 가정하는 것이 커리어의 대부분을 차지합니다. VC6로 10 년 동안 작업 한 결과, 성경 (표준이라고도 함)에 대한 이해가 부족한 수십 개의 패턴 (아마도 수백 개의 인스턴스)에 비해 이것이 수정되지 않은 컴파일러 버그라고 확신하는 하나를 발견했습니다.


디버그 버전에서는 종종 어설 션 및 / 또는 디버그 기호가 활성화됩니다. 이것은 다른 메모리 레이아웃으로 이어질 수 있습니다. 잘못된 포인터, 배열의 오버플로 또는 유사한 메모리 액세스의 경우 한 번은 중요한 잘못된 메모리 (예 : 함수 포인터)에 액세스하고 다른 경우에는 일부 중요하지 않은 메모리 (예 : 문서 문자열 만 폐기 됨)


명시 적으로 초기화되지 않은 변수는 릴리스 빌드에서 0이 될 수도 있고 그렇지 않을 수도 있습니다.


릴리스 빌드 (희망대로)는 디버그 빌드보다 빠르게 실행됩니다. 둘 이상의 스레드를 사용하는 경우 더 많은 인터리빙을 보거나 단순히 하나의 스레드가 다른 스레드보다 빠르게 실행되는 것을 볼 수 있습니다. 이는 디버그 빌드에서 눈치 채지 못할 수 있습니다.


나는 있었다 얼마 전에 비슷한 문제를 릴리스 빌드에서 다르게 처리되는 스택에 의해 발생되고있는 끝났다. 다를 수있는 기타 사항 :

  • 메모리 할당은 VS 컴파일러의 디버그 빌드에서 다르게 처리됩니다 (예 : 지워진 메모리에 0xcc 쓰기 등).
  • 루프 언 롤링 및 기타 컴파일러 최적화
  • 포인터의 하차

컴파일러 공급 업체와 DEBUG 플래그로 컴파일하는 라이브러리에 따라 다릅니다. DEBUG 코드는 실행중인 코드에 영향을주지 않아야하지만 (부작용이 없어야 함) 때때로 그렇습니다.

In particular, variables may be initialized only in DEBUG mode and left uninitialized in RELEASE mode. The STL in Visual Studio compilers are different in DEBUG and RELEASE modes. The idea is that iterators are fully checked in DEBUG to detect possible errors (using invalidated iterators, for example an iterator into a vector is invalidated if an insertion occurs after the iterator is retrieved).

The same happens with third party libraries, the first that I can think of is QT4, that will terminate your program with an assert if a thread different to the one that created the graphical object performs painting operations.

With all the changes, your code and memory footprint will be different in both modes. A pointer (reading the position one pass the end of an array) problem may pass undetected if that position is readable.

Assertions are meant to kill the application during DEBUG and disappear from RELEASE builds, so I would not think on assertions as being your problem. A rogue pointer or accessing one past the end would be my first suspects.

Some time ago there were problems with some compiler optimizations breaking code, but I have not read complaints lately. There could be an optimization problem there, but this would not be my first suspect.


Release builds are usually compiled with optimisation enabled in the compiler, while debug builds usually are not.

In some languages or when using many different libraries this can cause intermittent crashes - especially when the chosen optimization level is very high.

I know that this is the case with the gcc C++ compiler, but I'm not sure about Microsoft's compiler.


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

Due to the fact that guard bytes are added in debug builds, you may be able to "safely" access memory that is out-of-bounds for an array (particularly dynamic arrays), but this will cause an access violation in the release build. This error might go unnoticed, causing a corrupt heap and possibly an access violation in a place unrelated to the original error.

Use PageHeap (or, if you have Debugging Tools installed you could use gflags) to discover bugs related to corrupt heaps.

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


In my experience the most common reason seems to be that configurations differ in more ways than the release/build settings. E.g. different libs are included, or the debug build has a different stack size than the release build.

To avoid this in our Visual Studio 2005 projects we use property sheets extensively. This way the release and debug configurations can share common settings.


This post along with the links provided is very helpful in fixing related bug. adding to the above list, difference in calling conventions can also lead to this behavior - It failed in release build only with optimization for me. i declared as __stdcall and defined as __cdecl ( by default). [strangely this warning is not picked even in warn level 4 MSVC?]


Among optimizations that can be performed in Release mode (and no in Debug), copy elision can yield different results. More specifically RVO (return value optimization), depending on how your constructors are designed.

What are copy elision and return value optimization?

ReferenceURL : https://stackoverflow.com/questions/312312/what-are-some-reasons-a-release-build-would-run-differently-than-a-debug-build

반응형