분류 전체보기 (328)
.NET (111)
S/W tip (35)
etc (63)
DB (34)
HOT item~! (48)
Disign pettens (4)
UX (6)
나의 S/W (2)
개발관련 이슈 (16)
Diary (1)
웹플러스 (1)
calendar
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
tags
archive
link
ColorSwitch 00 01 02
▣  Debug와 Release모드의 차이 - .NET/C# - 2011. 6. 21. 13:25


프로젝트시 Debug에서 이상없이 실행되던 것이 Release로 컴파일하면 오류가 나는 경우
참고 사이트 : Http://sungod0.eglos.com3920875
 Debug mode vs Release mode

디버그 모드에서는 잘 돌아가는데 릴리즈 모드로 빌드해서 프로그램을 실행하면 뻑(?)이 나요. 왜 이럴까요?

이런 질문을 본적이 있거나 혹은 직접 경험해본 사람들이라면 이 버그를 잡는 고통을 잘 알것이다. 디버그와 릴리즈모드의 컴파일러 뒷단에서 일어나는 내용에 대해서 충분히 숙지 하지 못하고 있다면 이런 류의 버그를 잡기란 여간 까다로운 것이 아니다.

Visual Studio의 디버그 모드와 릴리즈 모드의 차이점은 무엇이고 어떤 일들이 일어나는지 본인의 경험, 웹상에서 찾은 정보들을 정리해두어 이런 버그로 고생하는데 도움(?)이 되었으면 한다.

 

Check List
•Pointer
초기화 되지 않은 포인터의 경우 디버그모드에서는 임의값 0xCD로 초기화를 수행하지만 릴리즈에서는 초기화를 수행하지 않는다. 디버그 모드에서 컴파일러 옵션을 조정하여 초기화 하지 않은 포인터 변수를 사용하는것을 예방 할 수 있다. /GZ 컴파일러 옵션은 기본적으로 VC++ 프로젝트 셋팅에서 기본값이 아니므로 필요하다면 추가해서 초기화 되지 않는 포인터의 값을 0xCC로 채우도록 해줘야 한다. /GZ 컴파일러 옵션의 가장 큰 목적은 초기화 하지 않은 메모리 변수의 값을 0xCCCCCCCC로 채워서 디버깅중에 개발자가 초기화 하지 않은 값임을 알 수 있도록 하는것이다.
◦디버그모드에서 deallocator에 의해 해제된 메모리에 채워지는 값은 0xDD 이다.
•Heap
디버그 모드에서 힙영역에 메모리를 할당하게 되면 guard byte( 0xFD로 초기화 )를 추가적으로 할당하여 가장 흔하게 범하는 zero-base의 arrary 인덱스를 잘못 계산하여 경계를 벗어난 영역을 접근하거나 지우려고 하는 코드를 작성했다고 하더라도 디버그 모드에서는 크래쉬가 발생하지 않을 수 있다. 이런 잠재적인 버그를 가진 프로그램을 릴리즈 모드에서 실행시키게 되면 크래쉬가 발생하게 된다.
•ASSERT
ASSERT 구문은 디버그 모드에서는 공백으로 대체되어지는 점을 잊고 아래와 같이 쓰게 되는 경우 이 코드는 릴리즈에서는 공백으로 대체되어 실제로 체크를 할 수 없게 된다.
ASSERT (OpenMyWindow () != NULL);위의 코드를 다음과 같이 바꾸게 되면 디버그와 릴리즈 모드 모두 정상적으로 동작하게 된다.
hWND = OpenMyWindow();ASSERT (hWND != NULL);이런 체크를 릴리즈에서도 하고 싶다면 VERITY 매크로를 사용하도록 하자.
•Prototypes 사용자 정의 메시지 처리를 위해 ON_MESSAGE 매크로를 사용중이라면 메시지 핸들러의 원형을 요구하는 타입에 정확하게 맞게 선언해줘야 한다. 디버그 모드에서는 원형에 일치하지 않더라도 컴파일러가 수정하여 동작하도록 만들어줘 버그를 발견하기 힘들게 만든다.
afx_msg LRESULT <class>::OnMyMessage (WPARAM wParam, LPARAM lParam);•Optimization Max Speed 옵션은 속도 최적화에 촛점을 맞추고 있기 때문에 최적화 과정에서 안전하지 않을수 있다. 기본적으로 릴리즈 모드에서는 Maximize Speed 옵션이 기본이지만 안전하게 속도 최적화를 보장하는 Minimize Size를 추천한다. 그리고, #pragma 지시자를 사용하여 특정 영역의 옵션을 설정 할 수 있다는것을 기억하자.
#pragma optimize("", off)// some code here #pragma optimize("", on)MSDN에서 권고하는 릴리즈 빌드 문제 해결
•ASSERT 문 검사
◦CheckList의 ASSERT
•디버그 빌드를 사용한 메모리 덮어쓰기 확인
1.InitInstance 함수의 맨 처음 부분에 다음 줄을 추가합니다. 이렇게 하면 디버그 메모리 할당자가 모든 할당된 메모리 주위에 보호 바이트를 배치합니다. 그러나 이 보호 바이트의 변경 여부(변경되었으면 메모리 덮어쓰기가 발생했음)를 확인하지 않으면 보호 바이트는 아무런 소용이 없습니다. 보호 바이트의 변경 여부를 확인하면 버퍼가 제공되어 메모리 덮어쓰기를 해결할 수 있습니다.

afxMemDF |= checkAlwaysMemDF;checkAlwaysMemDF 변수를 설정하면 MFC에서는 new 또는 delete가 호출될 때마다 AfxCheckMemory 함수를 호출하게 됩니다. 메모리 덮어쓰기가 감지된 경우에는 다음과 같은 TRACE 메시지가 생성됩니다.

Damage Occurred! Block=0x5533이러한 메시지가 표시되는 경우에는 코드를 단계별로 실행하여 손상된 부분을 확인해야 합니다. 메모리 덮어쓰기가 발생한 부분을 보다 정확하게 구별하려면 사용자가 AfxCheckMemory를 명시적으로 호출하면 됩니다. 예를 들면 다음과 같습니다.

ASSERT(AfxCheckMemory());    DoABunchOfStuff();ASSERT(AfxCheckMemory());첫 번째 ASSERT는 성공하고 두 번째 ASSERT는 실패하는 경우에는 두 호출 사이의 함수에서 메모리 덮어쓰기가 발생했을 가능성이 큽니다.

응용 프로그램의 특성에 따라 afxMemDF를 사용하면 프로그램 실행이 너무 느려져서 테스트조차 수행할 수 없는 경우도 있습니다. 왜냐하면afxMemDF 변수는 new 및 delete가 호출될 때마다 AfxCheckMemory가 호출되도록 하기 때문입니다. 이 경우에는 위의 예제와 같이 AfxCheckMemory( ) 호출을 분산시켜야 하며, 이러한 방법으로 메모리 덮어쓰기를 구별해야 합니다.

•릴리스 빌드에 대한 디버그 정보 생성 활성화
1.프로젝트의 속성 페이지 대화 상자를 엽니다. 자세한 내용은 Visual C++ 프로젝트 속성 설정을 참조하십시오.
2./Z7 또는 /Zi를 활성화합니다.
3./INCREMENTAL:NO를 선택합니다.
4./DEBUG:Yes를 선택합니다.
5./OPT:REF를 선택합니다.
6./OPT:ICF를 선택합니다.
◦이제 릴리스 빌드 응용 프로그램을 디버깅할 수 있습니다. 문제를 찾으려면 오류가 발생한 부분을 찾을 때까지 코드를 단계별로 실행하거나, Just-In-Time 디버깅을 사용하여 올바르지 않은 매개 변수 또는 코드를 확인합니다.

프로그램이 디버그 빌드에서는 작동하지만 릴리스 빌드에서 작동하지 않으면 소스 코드에서 컴파일러 최적화 중 하나에 결함이 있는 경우일 수 있습니다. 문제를 격리하려면 문제의 원인이 되는 최적화와 파일을 찾을 때까지 각 소스 코드 파일에 대해 선택한 최적화를 비활성화해야 합니다. 예를 들어, 파일을 두 그룹으로 나누고 한 그룹에서 최적화를 비활성화한 다음 문제가 파일 하나에서만 발생할 때까지 각 그룹을 계속 나눌 수 있습니다.

디버그 빌드에서 그러한 버그를 노출시키려면 /RTC를 사용합니다.

•메모리 덮어쓰기 확인
힙 조작 함수 호출 시 액세스 위반이 발생되면 프로그램이 힙을 손상시켰을 가능성이 있습니다. 이러한 경우의 일반적인 증상은 다음과 같습니다.
Access Violation in _searchseg_heapchk 함수는 디버그 빌드와 릴리스 빌드 모두에서(Windows NT에만 해당) 런타임 라이브러리 힙의 무결성을 확인하는 데 사용할 수 있습니다. _heapchk는 AfxCheckMemory 함수를 사용하여 힙 덮어쓰기를 확인하는 것과 같은 방법으로 사용할 수 있습니다. 예를 들면 다음과 같습니다.
if(_heapchk()!=_HEAPOK)   DebugBreak();이 함수가 실패하는 경우에는 힙이 손상된 시점을 확인해야 합니다.
Reference
•Debugging Release Mode Problems
•Debug vs Release mode differences when storing a delegate in a hashtable
•My app works in debug build, but crashes in release. What's the difference between the two?
•joelonsoftware "Problems with Release build (but not Debug)"
•HOWTO: 릴리즈 모드로 build 된 프로그램의 디버깅
tag: debug, release


  

========================================================================================================

mastojun.net/181
http://www.jongkok4.net/10

-릴리즈 모드
프로그램을 배포하기 위해 컴파일 하는 모드
-초기화 하지 않는다.
-같은 문자열 상수라도 서로다른 공간에 할당한다.
-디버깅정보를 삽입하지 않고 코드를 최적화하여 실행 파일 크기를 최대한 줄여준다.
-속도나 크기면에서 월등이 유리하다(메모리 점유율로 낮아지고 실행도 빨라짐)
-더이상 현재버전에서 내결함성이나 문제점들을 발견할 수 없었을때 빌드하여 주는 모드


-디버깅 모드
-컴파일시 들어가는 디버깅에 필요한 자질구리한 정보를 뺀 알짜 프로그램만 쏙 뽑아냄
-실행파일에 디버깅 정보를 삽입하여 언제든지 디버깅을 할 수 있도록 하며 Debug서브 폴더에 실행파일을 만들어준다.
-디버깅정보가 들어가 있기때문에 실행파일 상태를 확인할수 있다.
-디버그에 필요한 정보들을 실행시 계속 체크함으로써 속도가 느림


-디버그 빌드와 릴리즈 빌드에서 서로 실행 결과가 다른 경우?
특기 디버그 빌드에서는 괜찮은데 릴리즈 빌드에서만 오류가 발생하여 프로그램이 죽는 경우가 있는데
이런 경우는 대부분 메모리가 깨진 경우에 발생한다. 두 모드에서 동적으로 메모리를 할당하면 힙 영역에
요청한 크기만큼 메모리를 할당 받게 되는데 그 초기값이 다르다.

-릴리즈 모드와 디버깅모드의 차이점은?
디버깅 정보를 실행코드 안에 넣느냐 안넣느냐임
즉 디버거 모드로 컴파일하게되면 실행상태에서 추적할수 있는 정보가 실행파일 안에 들어가게 됨
그래서 용량이 커점
릴리즈는 디버깅 정보없어 순수한 소스코드자체의 기능만 컴파일되어 실행파일로 만들어짐


articles
recent replies
recent trackbacks
notice
Admin : New post