작성
·
405
·
수정됨
0
강사님 께서는:
SendBufferHelper(버퍼)가 세션 외부에 있는 상황은 바람직 하지만
플레이어 세션중(PacketSession)하나가 send() 처리를 못하고 이런 일회용 버퍼를 계속 물고 있을 수 있다.
(ex 사용자가 엘리베이터를 타서 통신이 안되는 경우)
그럼 참조정리를 못하니 GC가 수거를 안해간다.
이 버퍼 릭킹 문제를 처리하기 위해 레퍼런스 카운트를 적용할수도 있다 라고 말씀하셨는데. C#에서 이를 구현하는데 난관이 있어서요(그점도 이미 말씀하셨었죠), 아래와 같습니다.
레퍼런스 카운트 사용 방식 (예상)
만약 100명의 사용자에게 브로드 캐스팅 할경우 이 버퍼에 대한 레퍼런스 카운트를 100으로 세팅한다.
각 세션에서(100개) 각각 send에 성공해서 버퍼에 대한 참조가 끝날 때마다 1씩 감소시킨다.
이 카운트 감소 처리를 할때 쓰레드 동기화에 신경써야 한다.
문제 1 ) 이런 동기화 처리도 성능에 영향을 준다. 레퍼런스 카운트 처리 때문에 샌드함수는 결국 지연되는 것.
문제 2) 매번 다 쓰인 버퍼의 레퍼런스 카운트가 0이 되었다 한들, 그것을 GC가 "항상" "확실히" 수거해가는지 테스트할 방법을 모른다.
문제 3) 레퍼런스 카운트가 0이 안되고 1이 유지되어서 어딘가에서 send가 막혀있는걸 확인 했을때 그 세션을 Disconnect()한다고 해도 GC가 이 버퍼를 "항상", "확실히"수거해 갈지 알 수 없다 (테스트 방법의 부재)
그래서 아래와 같은 질문을 드립니다.
!! 질문 0 !!) 강사님께서 메모리 릭에 대한 우려가 있다고 말씀하셨는데, 그게 순전히 우려인지, 혹시 테스트를 해보신건지 궁금합니다.
다시 말해서 C#에서 샌드 리시브 버퍼를 그냥 쓰기로 강행하면 나중에 낭패 볼까요?
질문 1 ) 위의 2,3번 문제를 체크할 수 있는 방법이 있을까요?
질문 2 ) 요즘 C#서버가 많이 보입니다. 모두 이런 문제를 고려했을텐데요, 그냥 매 순간 지금처럼 조각조각 패킷을 만들어 보내는게 대세인가요? 아니면 다른 방법이 있나요?
질문 3) 위의 1번 문제의 성능 감소가 클까요?
질문 4) 혹시 버퍼 크기를 4096 * 100 이 아니라 250, 300 등 작게 잡으면 이문제를 무시해도 될까요?
P.S 이 강의 시리즈가 매우 큰 도움이 되고 있습니다. 감사합니다.
답변 1
1
네 간단히 질문4처럼 버퍼를 작게 잡아 사용하면 됩니다.
지금은 큰 조각을 잘라서 쓰니 어려운 것이죠.
메모리 릭에 대한 단순한 '우려'가 아니라 정말로 특정 클라에 전송이 밀리면 당연히 회수가 안됩니다.
그리고 엄밀히 말해 C# 참조는 refCount 방식이 아니라서
억지로 refCount를 사용하는 것은 포기하는게 정신 건강에 좋습니다.
굳이 SessionBuffer 풀링을 한다면 최대 크기에 해당하는 버퍼를 여러개 준비해놓고
그걸 돌려 쓰는게 가장 나을 것 같네요. (Chunk는 포기하고)