포트폴리오
Select 모델 서버 프로젝트 09 - 서버 루프가 갑자기 0으로 꺼지는 현상 해결
묭묭.cpp
2024. 10. 30. 18:46
Select 모델 서버 프로젝트 09 - 서버 루프가 갑자기 0으로 꺼지는 현상 해결
문제점
서버에서 7000개의 클라이언트 더미 테스트를 진행
- 30~40분에 한번씩 서버 FPS와 네트워크 Loop가 0으로 떨어지던 버그 발생
- 그리고 다시 회복되어 정상 작동
- 크래시 덤프를 남기고 디버깅을 해보자
크래시 덤프 코드 삽입
모니터링 스레드의 Update 루프에서
// FPS가 5으로 떨어지면 Crash 유도
if (m_lFPS < 5)
{
MonitoringFile(sessionCount, playerCount);
CCrashDump::Crash();
}
- FPS가 5 밑으로 떨어지면 서버의 크래시를 유도하고
- 서버가 크래시가 날 때까지 기다림
덤프 파일 확인
- 덤프 파일의 크기가 이상함
- 덤프 파일의 크기는 실제로 프로세스가 사용중인 메모리 크기임
- 딱 봐도 메모리 누수
- 일단 메모리 누수부터 잡자!
메모리 누수 잡기
가장 간단한 것부터 확인하기
- 가장 무식한 방법
- 비주얼 스튜디오에서 솔루션 대상으로 모든 new를 검색하여 추적
- 일단 모든 new와 delete를 추적해보자
- 여기서 잡히면 베스트
- 안잡히면 예전에 만들었던 new delete 오버로딩을 통한 추적기를 사용해볼 예정
Player와 Session 객체부터 확인
- 여기는 할당되는 곳과 할당 해제되는 코드의 위치가 다름
- 그리고 내가 직접 설계한 구조이기 때문에 어디서 할당 해제되는지 확실히 알고 있음
- 각각 해당하는 부분을 체크함
- 문제가 없었음
직렬화 버퍼
- 이것은 직접 할당한 코드의 생명주기에서 할당 해제해야 함
- 직접 할당 - new 가 아님
- CGenPacket을 통한 할당
- CGenPacket을 검색하여 추적
- 이곳이 문제였음
- CGameServer.cpp의 모든 부분이 해제를 안하고 있었음
- 가장 처음 테스트 용도로 짰었음...
- 모두 delete 코드를 넣어주고 확인
- 모니터링 결과 누수는 없었음
그럼 FPS 0은 왜 나왔는가?
FPS가 0으로 될 시점의 커널 CPU 사용률이 거의 25에 근접
- 유저 모드로는 거의 못 돌았다는 것
- 그런데 네트워크 TPS는 조금 조금씩 나옴
다른 케이스는
- 아예 스레드가 블락되어서 돌지 못했음
- CPU 사용률이 0에 근접
아래 로그는 모니터링 스레드를 Sleep 안걸고 Full로 돌릴 때의 케이스
// case 1
Process Usage
Total : 49.219566
User : 25.781677
Kernel : 23.437889
// case 2
Process Usage
Total : 28.525297
User : 23.836208
Kernel : 4.689090
덤프 파일을 확인한 결과 유의미한 결과를 얻지 못했음
- 스레드가 블록된 위치가 정확하지 않음
- 두 결과 모두 다른 위치
로컬에서 돌려보자
- 직접 로컬에서 테스트한 결과
- FPS가 0이 되는 상황이 많이 발생함
- CPU가 바쁘게 돌고 있어 내 서버 프로세스가 CPU를 점유하지 못하는 상태에서 0이 되는 건 확실
- 근데 아예 블록이 되는 건 이해되지 않음
FPS가 0이 되는 순간 서버 프로세스를 멈추어 봄
- 거의 모든 순간에 로그를 작성하기 직전에 멈추어 있었음
- 로그를 파일에 쓸 땐 SRWLock을 사용함
- 대부분의 상황에서 SRWLock 코드에서 걸려있음
- 로그를 정말 많이 써야할 상황임
- 정말 바쁜 상황에서 모니터링 코드에서도 락을 많이 검
- 상황이 잘못 맞아 네트워크 스레드의 SRWLock이 스핀 카운트를 모두 돌고 블락에 빠짐
- 혹은 저곳에서 스핀락을 돌고 있음
데드락은 아니었고 사실 정상적인 상황이었음
- 정말 서버가 바빠서 코드를 수행하지 못하고 있던 것
- 즉, 그냥 매우 느리게 동작함
위에서 메모리 누수를 잡고 서버에서 테스트한 결과
- FPS가 떨어지지 않고 잘 도는 것을 확인
그럼에도 찔끔찔끔 메모리가 오르는 현상을 확인
- std::unordered_map의 사이즈 확장 시 커진 사이즈를 그대로 냅둠
- 처음 서버 초기화 시점에 reserve를 수행하면 사용 메모리가 안정적인 것을 확인
- 아마 서버를 계속 켜뒀어도 메모리 누수는 아니고 적당히 오르다 안 올랐을 것
반응형