[CASE 1] 잘못된 메모리 사용
대부분의 경우 응용프로그램이 메모리를 잘못 사용해 문제가 발생한다.
[그림1] 응용프로그램 오류 예시. 아래의 3번 사례에 가깝다
1. 프로그램에서 문자열 등에 할당한 버퍼 길이보다 더 많은 메모리 사용할 때
2. 할당한 메모리 길이 보다 긴 길이의 문자열을 복사할 때
3. 잘못된 포인터 계산으로 잘못된 메모리 사용할 때
4. 잘못 만들어진 프로그램/소스코드에서 잘못된 메모리를 지시하여 원치 않은 동작이 발생할 때
5. 메모리 할당하고 해제 했으나 해당 해제된 메모리를 그대로 사용하는 소스코드 (보통 개발자 실수)
※ 도움될 만한 툴 : GFlags.exe, Windbg
- Windbg를 통해 원인 모듈까지 찾을 수 있지만 심볼을 설정해야 해당 함수 사용하는 소스 코드까지 확인 가능함
[CASE 2] 특정 프로세스의 CPU 사용률 100% 기록
하나의 스레드로 이뤄진 프로그램이라면 바로 확인 가능하나
멀티 스레드로 이뤄진 프로그램이라면 어떤 스레드가 CPU 자원 소모하고 있는지 파악하기 힘들다.
※ 도움될 만한 툴 : Process Explorer, Perfmon, Windbg
1. Process Explorer 사용
- 항상 CPU 자원 소모하는 주기가 일정할 경우 Process Explorer가 유용함
- Process Explorer를 통해 스레드 정보 / 스레드 스택 정보 확인 가능
→ 프로세스에서 CPU 자원 소모하는 스레드와 함수 찾을 수 있음
- 심볼이 없는 경우 어떤 스레드인지는 확인 가능하나 어떤 함수인지 확인까지는 어려울 수 있다.
- 심볼이 있다면 : Options > Configure Symbols 경로에서 심볼 위치 지정하여 분석
2. Perfmon (성능 모니터) 사용
- CPU 과다 사용이 “간헐적으로” 발생할 경우
- 시작 > 실행 > Perfmon.exe 실행
- 데이터 수집기 집합 > 사용자 정의 > 새로 만들기 > 템플릿으로부터 만들기 > 수동으로 만들기 > 카운터 추가 > Thread > % User Time > 확인 / 마침
- 각 스레드의 장기적인 사용 추이 확인
3. Windbg 사용
- 문제 발생하는 Process 확인 > Windbg 실행 > Attach to a Process 메뉴로 Process 붙이기
- 모든 스레드 스택 보기 (~*kb 명령어)
(ex) 스레드 中 USER32!NtUserGetMessage 함수 실행하는 스레드는 “메인 사용자 인터페이스” 위한 스레드
Sleep 함수를 호출하는 경우는 정상적인 제어를 갖고 있는 스레드
- 만약 5번 스레드를 더 자세히 봐야할 경우 >> ~5s 명령어 입력
[CASE 3] Deadlock 발생해 멈춘 경우
멀티스레드 프로그램의 데드락의 경우 Windbg를 통해 파악 가능
- 작업관리자에서 “응답 없음” 떨어져 있는 프로세스는 보통 데드락 발생 상태
- Windbg 실행 > 프로세스에서 동작 중인 스레드의 스택 정보를 모두 출력 > 데드락에 빠진 스레드가 어떤 동기화 객체를 기다리고 있는지 확인 > 해당 동기화 객체 소유하고 있는 스레드 정보 확인 + 스레드 스택 확인하여 동기화 객체를 풀어주지 않는 이유 확인
- 응답 없음 상태 프로세스를 Windbg 사용해 붙이고 ~*k 명령어로 콜스택 확인
(ex)
ღ kernel32!WaitForSIngleObject 함수가 발견되면 높은 확률. 해당 함수가 어떤 핸들을 기다리고 있는지
해당 함수가 띄워진 스택의 핸들 정보 확인 후 !handle xxxx 명령어로 확인
ღ 소스 코드가 확인이 된다면 해당 핸들이 특정 이벤트를 기다리고 있는 것을 확인할 수 있다.
ღ 이 단계까지 오면 Process Explorer를 통해 해당 이벤트 이름 검색하여 어떤 프로세스가 그 이벤트를 소유하고 있는지 확인 가능함
[CASE 4] 핸들 누수
- Windows 환경에서 파일 열기 : CreateFile() 함수 호출 > 핸들 획득 > 핸들에 사용하는 API 호출 > 사용 마친 후 CloseHandle() 함수를 통해 핸들을 닫음
- 응용프로그램의 오동작 혹은 버그로 핸들을 닫지 않는 경우 핸들 누수가 발생
→ 시스템은 닫지 않은 핸들을 관리하기 위해 정보를 커널 메모리에 지속 유지
→ 시스템 동작에 영향 (메모리 부족 등)
1. 작업관리자로 누수 확인
- 작업 관리자 통해 핸들 개수 확인 가능 (세부정보 > 열 선택 > 핸들)
- 핸들 개수는 확인 가능하나 어떤 핸들을 사용하고 있는지, 문제가 있는지(증가하고 있는지) 확인은 어려움
2. 성능 모니터로 누수 확인
- Perfmon 통해 Process 성능 개체의 Handle Count 값 추가해서 핸들 값 변화 추이 확인 가능
3. Process Explorer로 누수 확인
- View > Slow Lower Pane > Handle 선택 (혹은 Ctrl + H)
- 어떤 핸들이 생성되어 있는지는 확인 가능. 어떤 함수를 통해 핸들 생성됐는지 알 수 없음
- 결국은 작업관리자와 동일하게 추이까지는 확인이 어려움
4. Windbg로 누수 확인
- !Handle, !htrace 명령어로 핸들 정보 확인
- 핸들 시점의 콜스택 정보 확인 가능
- 핸들 누수 의심 프로그램 (Perfmon으로 특정 가능) > Windbg에 붙이기 > !htrace - enable 명령으로 핸들 생성 함수가 무엇인지 콜스택 저장
- 핸들 누수 의심 동작 시나리오가 있다면
→ 시나리오 실행 전 !htrace -snapshot 명령어 수행하여 현재 핸들 정보 저장
→ 핸들 누수 의심 동작 수행
→ !htrace -diff 명령 실행
→ 스냅샷 설정부터 !htrace -diff 명령어 전까지 열리고 닫힌 모든 핸들 정보 확인 가능
(프로세스, 스레드 정보와 함께 콜스택 출력되어 어떤 함수 경로 통해 핸들이 열리고 닫히는지 확인 가능)
[CASE 5] 메모리 누수 (Memory Leak)
- 메모리 사용 후에는 반드시 해제해줘야 한다.
- 메모리 사용량이 계속 증가하면 프로그래머 실수로 메모리 해제하지 않은 “Memory Leak” 의심
※ 32bit Application 가상 메모리 공간은 최대 2GB (커널 메모리가 2G 차지하기 때문에 4G는 아님)
※ 64bit Application 가상 메모리 공간은 최대 8TB
→ Out of Memory까지는 잘 뜨지 않지만 퍼포먼스에 영향 줄 수 있다.
1. 작업 관리자로 누수 확인
- Working Set : 해당 프로세스가 사용하는 물리 메모리의 양
- 특정 프로세스가 과도한 메모리를 사용하는 것을 의심한다면 “커밋 크기”를 확인
2. 성능 모니터로 누수 확인
- 장기간 누수가 발생하나 어떤 프로세스인지 특정하지 못한 경우 성능모니터를 사용
- Process 성능 개체의 Private Byte 를 모든 프로세스에 설정해 메모리 사용 증가량 확인
- 지속적으로 메모리 증가 그래프가 확인된다면 프로그램 제작사나 개발자가 문제 확인해야함
3. 재현 시나리오가 있는 경우 : UMDH(User Mode Dump Heap)로 확인
- CMD 창 > GFlags -i 프로세스명 +ust 로 유저모드 스택 추적 설정
- 재현 전에 콜스택 별 메모리 할당량 미리 기록
Umdh -pn:프로세스ID > c:\before.txt
- N회 재현 (재현 숫자는 경험치에 맡김. 보통 4~5회, 많으면 10회)
- 재현 후 콜스택 별 메모리 할당량 다시 기록
Umdh -pn:프로세스ID > c:\after_N.txt
- Before / After 정보 차이점 확인
Umdh c:\before.txt c:\after_N.txt > c:\diff.txt
Windows 기초 :: 작업 관리자 활용하기 (0) | 2020.07.18 |
---|---|
컴퓨터가 망가졌다 :: Windows 공부하기 (0) | 2020.07.18 |
윈도우(Windows) OS | 프로세스(Process), 스레드(Thread), 잡(Job) (0) | 2020.03.29 |
윈도우(Windows) OS | 시스인터널스 (Sysinternals) (0) | 2020.03.29 |
윈도우(Windows) OS | Debugging Tips (0) | 2020.03.23 |