2장에서는 전문 게임 개발자들이 널리 사용하는 툴을 살펴본다.
2.1 버전 컨트롤
공유 파일들을 갖고 여러 사용자가 함께 작업할 수 있게 도와주는 도구를 버전 컨트롤 시스템이라고 한다. 각 파일이 어떻게 바뀌었는지를 기록하기 때문에 변경 사항을 파악할 수 있고, 필요할 경우에는 예전 내용으로 되돌리는 것도 가능하다. 여러 사요ㅕㅇ자가 동시에 파일을 수정하는 것도 가능하며, 이 경우 서로의 작업을 망치지 않게 도와준다.
현업에서는 텍스트 파일 외에도 텍스처, 3D 멧, 애니메이션, 오디오 같은 바이너리 파일을 관리할 때도 소스코드와 동일한 버전 컨트롤 시스템을 사용한다.
2.1.1 버전 컨트롤을 쓰는 이유
- 모든 엔지니어가 공유하는 소스코드의 중심 저장소 (repository) 역할
- 모든 소스코드의 변경 사항을 기록
- 특정 상태나 시점의 소스코드에 태그를 달고 필요할 때 복원하는 기능
- 버전 브랜치 기능(데모나 패치 등을 만들고자 메인 개발 버전에서 분리된 버전)
2.1.2 널리 쓰이는 버전 컨트롤 시스템
참고:
- 페이스북에서는 빠른 기능 추가를 중요시 해서 Monorepo 를 사용한다.
- 한국 모바일 게임 업계 종사자에 의하면, Git(SourceTree, Tower) 이외에 SVN(Tortoise), PlasticSCM(유니티 제품)을 쓴다.
- Git의 경우 100MB 이상 대용량 파일을 업로드하는 경우 git lfs를 사용한다. 회사 조직 규모에 따라 GitHub에 따로 돈을 지불한다.
- NC는 유료 솔루션인 Perforce를 사용한다.
- SCCS와 RCS: 가장 오래된 버전 컨트롤 시스템. 커맨드 라인 기반, 유닉스환경에서 주로 쓰임.
- CVS: 전문가가 쓰기에 손색이 없는 툴, 커맨드 라인 기반. RCS 기반으로 만들어졌지만 지금은 완전히 독립. 유닉스 환경에서 주로 쓰이지만 윈도우 같은 다른 플랫폼에서도 쓸 수 있음. 오픈소스.
- Subversion: 오픈소스, CVS의 개량 대체 목적으로 만들어짐. 공짜. 학생이나 개인 프로젝트, 작은 스튜디오에 적합.
- Git: 리눅스 커널 등 유명 프로젝트에 많이 쓰임. 오픈소스. 프로그래머가 팡리을 수정한 후 먼저 이것을 브랜치에 올림. 프로그래머는 변경 사항을 다른 코드 브랜치 어디에나 쉽고 빠르게 적용할 수 있음. rebasing 이 가능. 여러 코드 브랜치를 다루는 데 특히 효과적. 분산형 버전 컨트롤 시스템.
- Perforce: 전문가용 소스 컨트롤 시스템. CUI, GUI 둘 다 지원. Change list(함께 수정된 파일들의 논리적 단위) 기능 때문에 유명. 주 저장소에 체크리스트를 저장할때는 우너자적 방식으로 저장(체크리스트의 모든 파일이 저장되거나 아니면 전부 저장되지 않음). 너티독, EA 등 여러 개발사에서 사용.
- NxN Alienbrain: 게임 개발에 특화된 버전 컨트롤 시스템. 다양하면서 강력한 기능 제공. 강점으로는 소스코드와 바이너리 파일들을 함께 저장할 수 있는 대용량 데이터 베이스 지원, 프로그래머를 비롯한 아티스트, 기획자 등 직군에 맞제 인터페이스를 바꿀 수 있다.
- ClearCase: 전문가용 버전 컨트롤 시스템, 대규모 소프트웨어 프로젝트에 특화. 강력한 성능, 윈도우 탐색기를 확장한 것 같은 독특한 인터페이스 제공, 가격이 비싸서 게임 개발에는 잘 사용되지 않음.
- 마이크로소프트 Visual SourceSafe: 파이크로소프트에서 개발한 간단한 소프 컨트롤 시스템, 일부 게임 개발에 성공적으로 사용된 예가 있음.
2.1.3 Subversion과 TortoiseSVN
Subversion을 특히 골라서 소개하는 이유는 공짜라는 점이 가장 크다. 필요한 기능을 고루 갖추고 있고 안정적이다. 윈도우 용으로는 TortoiseSVN이 좋고, 맥에서도 좋다.
다른 버전 컨트롤 시스템과 마찬가지로 Subversion은 클라이언트-서버 구조다.
여러 호스팅 서비스가 있다. (HelixTeamHub, Beanstalk)
2.1.4 코드 저장소 설정
제일 쉽게 서브버전을 시작하려면 HelixTeamHub 등의 SVN 호스팅 서비스를 찾아가 서브버전 저장소를 구성하면 된다.
저장소를 만든 후에는 통상적으로 호스팅 서비스의 웹사이트에서 간리할 수 있다.
2.1.5 TortoiseSVN 설치
TortoiseSVN은 인기 있는 서브버전 클라이언트다.
https://tortoisesvn.net/downloads.html 에 접속해 다운로드해서 설치하면 된다.
설치 후에는 아무 폴더에서나 우클릭을 하면, TortoiseSVN메뉴가 보인다.
이미 있는 저장소에 접속하려면
2.1.6 파일 버전, 업데이트, 커밋
- 일을 할 때는 프로그래마다 자기 로컬 머신에 소스코드를 다운로드 해야 한다. (TortoiseSVN의 경우 체크아웃하면 된다.)
- 주기적으로 다른 프로그래머의 작업 내용을 반영해야 한다. (우클릭 후 SVN Update)
- 일단 다운로드한 파일은 다른 프로그래머에 전혀 영향을 주지 않고 작업할 수 있다.
- 작업 후 커밋(commit)을 통해 다른 사람과 공유한다.
- 커밋하는 동안 서브버전은 로컬의 코드와 저장소의 최신 코드를 비교한다(diff).
2.1.7 다중 체크아웃, 브랜치, 합치기
독점적 체크아웃: 독점적 체크아웃은 같은 파일을 동시에 여러 사람이 수정할 수 없는 시스템. 파일을 수정하려면 먼저 체크아웃을 해서 그 파일을 잠근 후에야 작업할 수 있다. 체크아웃하징 낳은 파일은 로컬 머신에서 전부 읽기 전용 상태다. 작업을 마치면 체크인하는데, 잠금을 해제하고 변경 사항을 저장소에 저장해 다른 사람과 공유한다는 뜻이다.
서브버전이나 CVS, Perforce 등 괜찮은 버전 컨트롤 시스템은 다중 체크아웃 기능을 지원한다. 다른 사람이 작업 중인 파일을 동시에 수정할 수 있다.
먼저 체크인한 사람의 파일이 저장소의 최신 버전이 되고, 나중에 체크인하는 사람은 자신의 파일과 저장소의 최신 버전 간에 합치기를 해야 한다.
합치기는 보통 별 문제가 없는 경우가 많고 충돌이 생기더라도 소스 컨트롤이 자동으로 해결할 수 있는 경우도 있다. 서로 다른 장소에서 변경이 발생했ㅆ다면 자동으로 합치는데 전혀 문제가 없다. 반면 두 사람이 동시에 같은 위치에 작업을 했다면 커밋하는 프로그래머는 3자(3-way) 합치기를 해야한다.
서브버전은 독점적 체크아웃을 할 필요가 없고 로컬 머신의 모든 파일을 그냥 수정하면 된다. 작가의 사견으로는 바로 이 점이 서브버전을 대규모 프로젝트에 사용하기 어려운 주된 이유다.
어떤 파일을 수정했는지 정확히 파악하는 Perforce 같은 버전 컨트롤 시스템이 코드 수가 많은 프로젝트에 더 적합하다.
2.1.8 파일 지우기
저장소에서 파일이 지워졌더라도 완전히 사라진것은 아니다. 저장소에 있기는 하지만 최신 버전이 지워진 상태로 표시된 파일이기 때문에 로컬 머신에 다운로드하지 않을 뿐이다.
지워진 파일을 다시 저장소에서 복구하려면 지워지기 직전의 버전을 받은 후 그냥 다시 커밋하면 된다.
2.2 컴파일러, 링커, IDE
C++ 같은 컴파일 언어를 갖고 실행 프로그램을 만들려면 컴파일러와 링커가 필요하다. 윈도우에서 가장 널리 쓰이는 것은 마이크로소프트 비주얼 스튜디오다.
2.2.1 소스 파일, 헤더 파일, 번역 단위
- C++로 작성한 프로그램을 담고 있는 파일을 소스 파일이라고 한다. (.c, .cc, .cxx, .cpp ...)
- 소스 파일은 기술적인 용어로 번역 단위(translation unit)라고 부르기도 하는데 컴파일러가 한 번에 기계어 코드로 바꾸는 단위이기 때문이다.
- 헤더 파일은 특수한 형태의 소스 파일로, 타입 선언, 함수 프로토타입 같은 정보를 번역 단위 간에 공유하는 데 쓰인다. 컴파일러는 헤더 파일이 존재하는지 모른다. C++ 전처리기가 컴파일에 앞서 모든 #include 문을 헤더 파일의 내용으로 교체해 넣기 때문이다. (즉, 헤더 파일은 사람이 보기에만 독립적인 파일이다.)
2.2.2 라이브러리, 실행 파일, 동적 링크 라이브러리
번역 단위 1개가 컴파일된 결과물인 기계어는 object 파일에 저장된다(윈도우에서는 .obj, 유닉스에서는 .o). Object 파일 안의 기계어는 다음과 같은 특성이 있다.
- 재배치 가능: 코드가 위치할 메모리 주소가 아직 결정되지 않은 상태다.
- 링크되지 않음: 번역 단위 안에 들어 있지 않은 외부 참조 함수나 전역 데이터가 아직 확정되지 않았다.
라이브러리
object 파일 여러 개를 묶은 것이 라이브러리다.
라이브러리는 zip 파일이나 tar 파일과 비슷하게 단순한 파일의 모음이다. (여러 object 파일의 모음)
object 파일과 라이브러리는 링커를 거쳐 실행 파일로 변환된다. 이 과정을 '링크한다'고 말한다. 컴파일러에서 정하지 않고 남겨 뒀던 메모리 주소 값이나 외부 참조를 확정한(resolved) 상태의 기계어가 실행 파일이며, 운영체제에서 로드하고 실행할 수 있다.
링커의 역할
- 모든 기계어 명령어의 최종 상대 주소를 계산한다. 프로그램이 실행될 때 메모리에 올라갈 모양이 된다.
- 각 번역 단위(object파일)에서 확정하지 못했던 외부 함수와 전역 데이터의 값을 확정한다.
짚고 넘어가야 할 점은 실행 파일의 기계어 코드는 여전히 '재배치 가능하다(relocatable)'는 점이다. 이 말은 모든 기계어와 데이터를 가리키는 메모리 주소는 절대적으로 고정된 주소가 아니라 기준 값에 더해질 상대적인 값이라는 뜻이다. 절대 메모리 주소는 실행 파일이 실행되기 직전에 메모리에 로드될 때 결정된다.
동적 링크 라이브러리(DLL)
- 동적 링크 라이브러리(DLL)는 라이브러리의 한 종류
- 보통 정적 라이브러리와 실행 파일의 중간 형태를 띤다
- DLL은 실행 파일에서 호출할 수 있는 함수를 담고 있다는 점에서는 라이브러리와 같고
- 운영체제가 따로 로드한다는 점은 실행 파일과 같다.
- C++ 실행 파일의 main()과 비슷한 형태의 시작과 끝을 처리하는 코드가 있다는 점도 실행 파일과 유사하다.
- 실행 파일이 DLL을 사용하려면 부분적으로 링크(partially linked)된 기계어 코드가 있어야 한다.
- 링크를 거치면 대부분의 함수와 데이터에 대한 메모리 주소가 결정되지만 DLL안에 포함된 함수에 대한 참조는 결정되지 않는다. (그래서 부분적으로 링크됐다고 한다).
- 나중에 실행 파일을 실행 할 때 운영체제에서 참조가 결정되지 않은 함수들을 찾아 필요한 DLL을 메모리에 로드한 후 참조 값을 갱신한다.
- 실행 파일과 상관없이 DLL만 교체할 수 있다는 점에서 유용.
2.2.3 프로젝트와 솔루션
비주얼 스튜디오에서 프로젝트란 소스 파일 모음으로 컴파일해서 라이브러리나 실행 파일, DLL을 만드는 일을 한다.
- VS 2013 이후의 모든 비주얼 스튜디오의 프록젝트파일은 .vcxproj 확장자를 가진다.
- 이 파일들은 XML 형태이므로 사람이 읽고 이해할 수 있으며 필요하면 고칠 수도 있다.
- 비주얼 스튜디오 2003부터는 솔루션(.sln) 개념을 도입했는데, 여러 프로젝트를 관리하고자 도입된 개념
- 솔루션은 서로 의존적이거나 아니면 독립적인 프로젝트의 모음
- 여러 라이브러리와 실행 파일, DLL을 만든다.
- 솔루션 탐색기는 트리 모양의 구조 (실제 디스크에 위치한 폴더와는 상관 없음, 디스크 폴더 구조를 그대로 프로젝트에 사용하는것이 일반적이긴 함)
2.2.4 빌드 설정
C/C++ 전처리기, 컴파일러, 링커는 다양한 옵션을 통해 동작을 세부 조정 가능.
옵션은 보통 컴파일러를 실행할 때 커맨드라인 인자로 지정.
마이크로소프트 컴파일러의 예시
C:\> cl /c foo.cpp /Fo foo.obj /Wall /Od /Zi
LLVM/Clang의 예시
clang --std=c++14 foo.cpp -o foo.o --Wall -O0 -g
현대의 컴파일러는 정말 많은 옵션이 있기 때문에 매번 코드 빌드시 마다 옵션을 일일히 지정하면 실수하기 쉽다. 그래서 사용하는 것이 빌드 설정이다.
2.2.4.1 기본적인 빌드 설정
전처리기 설정
오늘날 C++ 전처리기에서 지원하는 기능 중 매우 유용한것은 커맨드라인 옵션으로 매크로를 정의하는 기능.
- 이렇게 정의된 매크로는 소스코드의 #define 구문 매크로와 차이가 없음
- -D 나 /D 옵션으로 지정, 개수 제한 없음.
- 소스코드를 고치지 않으면서 다양한 빌드 설정을 코드에 적용 가능
흔히 보이는 _DEBUG 심볼은 디버그 빌드에서 정의되는 것인데, 디버그 아닌 빌드에서는 NDEBUG가 대신 정의된다.
이를 조건부 컴파일(conditional compile)이라고 한다.
void f()
{
#ifdef _DEBUG
printf("Calling fuinction f()\n");
#endif
// ...
}
컴파일하는 환경이나 대상이 되는 플랫폼 정보를 바탕으로 컴파일러가 임의로 매크로를 정의하는 경우도 있다.
__cplusplus
_MS_VER
__GNUC__
_WIN32
컴파일러 옵션
- 컴파일러 옵션 중에 제일 흔히 쓰이는 것이 object 파일에 디버그 정보를 포함할지를 지정하는 옵션이다.
디버그 정보를 포함하면 실행파일 크기가 커지고 해커가 역엔지니어링하는 단서가 되기 때문에 항상 최종 버전에는 디버그 정보를 뺀다.
- 인라인 함수를 펼칠(expand)것인지 아닌지 정하는 옵션
펼침을 끄면 인라인 함수는 여느 함수와 마찬가지로 메모리 한 곳에 존재하는 함수가 됨. 이렇게 되면 디버깅은 용이해지지만 인라인 함수 본래 목적인 실행 속도 향상은 기대할 수 없음.
- 얼마나 적극적으로 최적화 시도를 할지 최적화 방법 등을 지정 가능
코드 실행 순서가 달라지기도, 변수가 사라지기도, 레지스터 사용이 바뀌는 등의 변화가 일어난다. 따라서 최적화된 코드는 디버거로 디버깅하기 매우 어렵다. 디버그 빌드에서는 모든 최적화를 끄고 사용.
링커 설정
링커도 여러 옵션을 바꿀 수 있다.
보통 디버그 빌드에서는 디버그용 라이브러리를 링크하고, 디버그가 아닌 빌드에서는 최적화된 라이브러리를 사용한다.
- 스택 크기
- 실행 파일이 메모리에 올라갈 기본 주소(base address) 지정
- 대상 하드웨어 지정(하드웨어별 최적화)
- 글로벌(링크 시) 최적화를 수행할지 여부
등 다양한 옵션이 있다.
2.2.4.2 로컬 또는 글로벌 최적화
최적화는 다음과 같은 두 가지 형태로 수행된다.
로컬 최적화
기본 블록(basic block)이라는 작은 코드 범위에서만 수행된다. 기본 블록은 분기가 없는 연속된 어셈블리 명령어들이다.
- 수리 연산 단순화
- 연산 강도 경감(strength reduction)
예) x/2를 x >> 1 로 바꾸는 것.
- 코드 인라인화(inlining)
- 상수 폴딩(folding)
- 상수 전파(propagation)
- 루프 펼치기(loop unrolling)
- 죽은 코드 제거(dead code elimination)
- 명령어 재배열(CPU 파이프라인 stall 최소화)
글로벌 최적화
기본 블록의 범위를 벗어난 최적화.
전체 프로글매의 제어 흐름 그래프를 고려해야 한다.
ex) 공통 하부 표현식 제거(common sub-expression elimination)
글로벌 최적화는 번역 단위를 넘나들어야하기 때문에 컴파일러보다는 링커가 수행.
-> 링커 타임 최적화(LTO, Linker Time Optimization)
프로파일 가이디드 최적화
- 현대화된 컴파일러가 지원.
- 프로그램이 실행되는 동안 수집한 정보를 통해 퍼포먼스에 가장 중요한 코드 경로를 반복적으로 찾아 최적화.
2.2.4.3 흔히 사용하는 빌드 설정
- 디버그 빌드(debug build):
- 모든 최적화를 끔
- 인라인 함수 펼침 끔
- 디버그 정보를 최대한 갖고 있음
- 느림
- 개발 빌드(development build):
- 빠른 버전
- 대부분의 최적화 적용
- 디버그 정보와 assertion은 켬
- 최종 제품에 비견될 정도로 빠르면서 디버그 가능
- 출시 빌드(ship build):
- 고객에게 전달될 마지막 형태
- 최종 빌드나 디스크 빌드라고도 함
- 모든 디버그 정보 제거
- assertion 전부 제거하거나 일부만 남김
- 글로벌 최적화를 포함한 가능한 많은 최적화 적용
- 디버그 어렵지만 가장 빠르고 가벼움
혼합 빌드
- Hybrid build 란 일부분의 번역 단위만 디버그 버전으로 빌드하고 나머지는 개발로 빌드.
- 관심 있는 코드를 디버깅 하는 동안 나머지 부분은 속도 저하 없이 실행.
빌드 설정과 테스트 용이성
- 빌드 설정을 여러 개 사용할수록 테스트는 어려워짐.
- 어떤 빌드에서만 오류 발생 할 수도 있음.
- 모든 빌드를 엄밀하게 테스트 해야함.
2.2.4.4 프로젝트 설정
다음 네 가지를 가장 많이 사용
- 구성 속성/일반
- 구성 속성/디버깅
- 구성 속성/C++
- 구성 속성/링커
자세한 설명은 생략.
2.2.5 코드 디버깅
코드 디버깅은 프로그래머가 익혀야 할 기술 중 매우 중요.
비주얼 스튜디오 중심으로 설명하지만 다른 디버거들도 이에 상응하는 기술이 있을것이기 때문에 참고.
2.2.5.1 시작 프로젝트
- 비주얼 스튜디오에서 솔루션은 여러 개의 프로젝트를 포함할 수 있다.
- 실행 파일을 만드는 프로젝트, 라이브러리나 DLL 만드는 프로젝트 등
- 비주얼 스튜디오에는 시작 프로젝트 라는 개념이 있다.
- 디버거가 현재 디버깅할 프로젝트
- 보통 1개의 시작 프로젝트를 설정
- 프로그래머는 1개의 프로젝트에 디버깅 수행
- 여러 개 동시 디버깅도 가능하긴 함
2.2.5.2 중단점
- Breakpoint 는 코드 디버깅 시 가장 많이 쓰이는 도구.
- 소스코드의 라인 실행 직전 프로그램 실행 멈추라고 지시
2.2.5.3 코드 따라가며 디버깅
- 중단점 도달 시 F10 키를 눌러 한 단계식 코드를 따라갈 수 있음
- F11 을 누르면 함수 안으로 들어간다.
- F10 을 누르면 함수를 지나간다.
2.2.5.4 콜 스택
- 프로그램 실행 중 어느 시점에 호출된 함수의 더미(스택)를 의미
- 중단점에 중지시킨 후 콜 스택 윈도우에서 더블클릭해서 콜 스택을 탐색할 수 있음.
2.2.5.5 조사식 창(watch window)
- 프로그램의 여러 변수 값을 보고 싶을 때 사용.
2.2.5.6 데이터 중단점(data breakpoint)
- 일반적 중단점과 다른 원리로 동작.
- 어떤 메모리 주소에 값이 써질 때(즉 값이 변경됐을 때)를 감지.
- 하드웨어 중단점(hardware breakpoint) 이라고도 부름.
2.2.5.7 중단점 조건
- 중단점에 조건을 설정하거나 히트(hit) 카운트를 지정 가능
- 조건문 검사가 들어가기 때문에 느려질 수 있음
2.2.5.8 최적화된 빌드 디버깅
- 앞서 말했듯 최적화된 빌드는 디버깅이 어렵다.
- 상황이 여의치 않아 이 빌드에서 디버깅 해야 할때도 있음.
- 개발자들이 두려워 하는 릴리스 빌드에서만 생기는 버그는 변수를 초기화하지 않아 생기는 경우가 많다.
- 디버그 버전에서는 변수나 할당한 메모리가 0으로 초기화 되는 경우가 많지만 릴리스 버전에서는 그렇지 않기 때문.
- 릴리스 코드에서 코드가 생략되는 경우(assert 문 안에 중요한 코드가 들어간 경우)
- 디버그와 릴리스 빌드 간에 자료 구조의 크기나 패킹(packing)이 다를 때.
- 인라인 함수나 컴파일러 최적화 때문에
- 가끔 컴파일러 최적화 자체의 버그 등...
릴리스 빌드로 디버깅하는 기술은 꼭 익혀야 한다
- 디버거의 디스어셈블리를 읽을 줄 아는 능력 키우기
- 레지스터를 해석해 변수 값이나 메모리 주소를 알아내기
- 주소만 갖고 변수나 객체의 내용을 알아내기
- 정적 변수와 전역 변수를 활용하기
- 코드를 고치기: 재현이 쉬운 경우, 메시지 출력 코드를 넣거나, 문제 파악 할 수 있는 코드 추가, 등...
2.3 프로파일링 툴
다소 비과학적이긴 하지만 파레토 법칙이라는 것이 있다.(전체 효과의 80%는 겨우 20%에 의해 좌우된다는 의미)
- 전체 버그 80%는 20%의 코드를 수정함으로써 고칠 수 있다.
- 실행시간의 80&는 20%이하의 코드를 실행하는데 걸린다.
최적화 해야할 20%의 코드는 어떻게 찾는가? -> 프로파일러
- 코드가 실행되는 시간을 측정
- 각 함수별로 실행되는 데 걸린 시간을 알려 준다
- 이 정보를 이용해 가장 실행 시간을 많이 차지하는 함수부터 최적화.
함수가 몇 번 불렸는지 알면
- 함수 자체가 실행하는 데 시간이 오래 걸리는 경우
- 함수가 자주 불리는 경우
구분 가능.
프로파일러는 크게 두 가지 부류로 나눌 수 있다.
- 통계 방식 프로파일러:
- 프로그램 실행에 영향을 주지 않게 만들어짐
- 원리: CPU의 프로그램 카운터를 주기적 샘플링, 어떤 함수가 실행중인지 알아냄
- 예: 인텔의 VTune
- 인스트루먼트 방식의 프로파일러:
- 가장 정확하고 폭넓은 정보를 제공
- 프로그램 실행 속도는 매우 느려짐
- 원리: 프로그램을 미리 가공해서 함수마다 시작과 끝을 나타내는 임의의 코드 삽입
- 예: IBM의 Rational Purify Plus 툴킷에 포함된 Rational Quantify
마이크로소프트의 LOP(Low-Overhead Profiler)는 이 두 종류의 혼합.
2.4 메모리 누수와 오염 방지
- 메모리 누수: 할당된 메모리가 제때 해제되지 않는 것. 메모리 부족까지 초래 가능
- 메모리 오염: 엉뚱한 메모리 주소를 변경해 원래 있던 정보를 날려 버리고 변경됐어야 할 메모리 위치 값은 고쳐지지 않음.
둘 다 포인터 때문에 발생.
포인터 관련된 메모리 문제를 피하는 방법 중 하나는 좋은 코딩 습관을 들이는 것.
작가는 IBM의 래셔널 퓨리파이 툴을 선호.
파라소프트의 Insure++, Valgrind 개발자들의 밸그린드가 유명.
2.5 기타 툴
- 비교 툴(diff tool):
텍스트 파일 2개를 비교해서 어떤 부분이 다른지 알려줌
- 3자 합치기 툴:
동시에 같은 파일에 작업 할 경우 합치기 두번 해야 함 이때 합치는 툴을 3자 합치기 툴이라고 함.
- 헥스 에디터(Hex editors):
헥스 에디터란 바이너리 파일을 살펴보고 고칠 수 있는 툴. 데이터를 16진수 형태로 보여주는 데서 이름 유래.