채팅서버를 그냥 켜두면 메모리가 미친 거마냥 올라가는 상황이 관측됫다.

25MB쯤에서부터 시작하는데 18초만에 이렇게 늘어나는것이다.
4시간 쯤 뻘짓을 하다가 결국에 귀차니즘을 이겨내고 디버깅용 우아한 종료 함수를 만들기 시작햇다.
우아한 종료 함수는 별게 아니고 그냥 서버 멈추고 모든 리소스를 해제하는것이다.

락 프리 오브젝트 풀에서 모든 남아있는 size를 할당 해제하는 코드이다.
Capacity_ : 동적할당된 총량
size_ : 현재 프리리스트에 돌아온량
따라서 ClearAll을 진행한 시점에서는 size_는 무조건 0이고, Capacity_가 0보다 크면 그만큼이 메모리 누수이다.

서버종료하는 함수에서 이런식으로 모든 풀을 비운다.(당연히 이때까지 전부 모든 자원들이 풀에 반환되도록 코드를 구성해야한다, 이를 위해서 메시지큐를 전부 비우고, 세션을 전부 끊었다.)

결국 직렬화 버퍼풀에서 37911개의 릭이 낫다는 것을 깨닫게 된다.
(capacity_ == 1은 더미노드이다)
문제는 직렬화 버퍼는 컨텐츠나 네트워크 라이브러리에서 전부 사용하므로 할당하는 지점이 너무많다는 문제가 존재했다.
결국 할당할때마다 할당 사유에 따라 따라 직렬화버퍼에 이름을 붙이고 자료구조에 넣고,
해제할때는 자료구조에서 빼서 어디서 할당된 직렬화 버퍼가 제대로 해제되지 않는지를 추적해야만 햇다.

위와 같이 직렬화버퍼에 debugList라는 리스트를 멤버로 선언하고 할당 사유를 enum class로 만든다

allocType은 할당시 할당 사유를 저장할 멤버이며
cs_for_debug_leak은 직렬화 버퍼 할당은 여러 스레드에서 동시에 하는것이 전제라 락프리오브젝트 풀을 사용한다.
문제는 이때 직렬화 버퍼를 삽입할 std::list는 스레드 안전하지 않기때문에 락을 걸어야햇기에 선언되엇다

Alloc에서 할당 사유를 직렬화 버퍼에 멤버로 저장하고 락걸고 리스트에 넣는다
Free에서 락걸고 리스트에서 뺀다.

서버 종료함수에서 모든 리소스해제하고 중단점 걸고보면 직렬화 버퍼풀에서 릭난 갯수와 디버그 리스트의 갯수가 정확히 일치한다

해당 리스트 내에서 할당사유가 전부 ON_RECV이다.

중간 중간 if문에서 return 하거나 break하는 부분에 직렬화 버퍼를 해제하는부분이 빠졋음을 깨닫는다.
실제로 그부분에 중단점도 걸리는걸 확인햇다.

고치니까 잘된다.
'디버그 기록' 카테고리의 다른 글
| 채팅서버 메모리 누수 시즌2 (0) | 2024.10.28 |
|---|