Microsoft MVP성태의 닷넷 이야기
Socket 관련 Leak (OverlappedAsyncResult, OverlappedData) 관련 문의 [링크 복사], [링크+제목 복사]
조회: 3732
글쓴 사람
Syong (ianstory01 at naver.com)
홈페이지
첨부 파일

안녕하세요. .netFramework 4.5 사용 중인데, 최근 소켓 관련해서 해결하지 못하고 있는 문제가
있어 도움을 받고자 문의드립니다.

여러 대의 PC에서 동일한 프로그램으로 장비를 운영 중인데,
며칠이 지나서 보면 불규칙하게 메모리가 증가해있더라구요.
현장에서 메모리 분석을 할 수 없어 노트북으로 재현을 해봐도 나오지 않았는데,
오늘 우연히 딱 한 번 어떤 이유에서인지 재현이 되어 메모리를 확인할 수 있었는데,
OverlappedAsyncResult, OverlappedData 이 쪽에서 메모리가 급증해있더라구요.
조금 찾아보니 제가 Socket을 Async로 연결, 송수신을 처리했었는데,
구글링을 해보니 관련 이슈가 있는 건 알겠는데 명확히 해결 된 사례를 보지 못해서요ㅠ
연결, 메시지 송수신에 관련된 부분에 관한 소스를 첨부합니다.
Leak이라면, 일정 시간, 일정 주기로 항상 재현이 되야할 것 같은데...
그렇지 않아 어렵네요 ㅠ








[최초 등록일: ]
[최종 수정일: 2/14/2023]


비밀번호

댓글 작성자
 



2023-02-15 08시34분
제시하신 소켓 소스 코드로 재현 상황을 만들어 보세요. 운영 중인 것과 몇 배속으로 dummy 데이터 입/출력을 해보시고, 재현이 되면 그 프로젝트를 올려주세요.

재현이 안 되면, 가정만 하게 되고 그걸로 핑퐁하다 보면 시간만 갈 뿐입니다. 일례로... "EndReceive/EndSend 시에 예외가 발생할 수 있을 텐데, 그때 왜 소켓을 닫지 않는 거죠?"라고 말한 다음... ^^ 응답을 기다리다 그건 이러저러해서 처리가 되었다고 하면 또 다른 가정을 하게 될 것입니다.

(참고로, 운영에서 재현이 잘 된다면 고객 측에 양해를 구하고 잠깐 메모리 덤프를 떠서 사후 분석해 보는 것은 어떨까요?!!)
정성태
2023-02-21 07시33분
[Syong] 재현도 너무 불규칙하게 되는지라... 발생 조건을 아직 명확히 몰라서요...
메모리 프로파일러는 돌려봤는데.. 혹시 System.Threading.PinnableBufferCache가 쌓이는 것 같은데,
(ConcurrentStack<T>+Node<object>가 증가해서 내용을 봤더니 PinnableBufferCache) 가 있더라구요.
혹시 이게 뭘까요??ㅠ
[guest]
2023-02-21 08시24분
아래의 글로 정리했으니 한번 참고하세요.

C# - 비동기 소켓 사용 시 메모리 해제가 finalizer 단계에서 발생하는 사례
; https://www.sysnet.pe.kr/2/0/13267

그나저나, 해당 메모리가 끝없이 늘고 있나요? 아니면 어느 정도만 늘고 있나요? 만약 전자의 경우라면 Socket.Close만 제대로 해줘도 그런 현상이 사라질 것입니다. 반면, 후자의 경우라면 어떤 식으로든 해당 개체의 참조를 유지하고 있는 측이 있으므로 그것을 찾아 해결을 하셔야 합니다.
정성태
2023-02-23 01시41분
[Syong] 답변 글 확인했습니다! 자세한 답변 감사합니다.
이번 문제 관련해서 로그 분석 과정에서 새롭게 확인된 내용이 있어 테스트 결과 재현이 되었는데요,
메모리가 증가하는 시점부터 SendCallback 함수에 넣어둔 Send에 관한 로그가 찍히지 않아 확인해보니,
Callback 함수로 들어오지 않고 있더라구요(50ms 간격으로 두 프로그램 간 계속 통신해야하는데, 설비마다 각기 다른 시간(1~4일)이 지나고 지난 후). 그래서 테스트 프로그램으로 대용량 메시지를 만들어서 BeginSend로 메시지를 전달해보니 실제로 메시지가 전달되지도 않고, Callback 함수도 타지 않으며 메모리 누수가 발생하더라구요.
다른 방법으로 Send는 비동기로 하지않고, 동기로 하고 같은 대용량 메시지를 전달해도 메시지가 잘 전달되고, 누수도 발생하지 않았습니다. BeginSend와 Callback 처리에서 메모리가 누수되고 있는데, 이에 대해 처리해줘야하는 내용이 있을까요?
한가지 더 질문은 Send를 비동기로 처리했던 이유는 Callback 함수로 들어왔다면 확실히 전송되었다고 판단하고 로그를 찍기 위함이었습니다.
[guest]
2023-02-23 02시28분
대용량으로 보냈을 때 SendCallback이 호출되지 않는 것은 상황에 따라 그럴 수 있습니다.

Socket의 Send 동작은 SendBufferSize 크기의 메모리가 여유가 있을 때입니다. 쉽게 예를 들어 SendBufferSize가 4KB이고 그렇게 정해진 버퍼에 현재 전송되지 않은 데이터가 2KB가 쌓여 있는 중에 뒤이어 send(4KB)가 들어오면 SendBuffer가 담을 수 없으므로 blocking이 생깁니다.

위의 시나리오를 비동기로 따져보면, async_send(4KB)를 한 경우 전송 버퍼에 담지 못했으므로 SendCallback이 발생하지 않습니다. 그러면서 전달된 4KB는 메모리에 있게 되는데요, 그런 식으로 대용량 send가 발생하면 마치 메모리 릭이 발생하는 것처럼 보이는 것뿐입니다.

여기서 문제는 "receive를 하는 Socket Server"가 될 수 있습니다. 서버 측에서 Receive를 하지 않아 TCP 입력 버퍼가 비어 있지 않게 되고 (또는, 클라이언트 측에서 전송하는 데이터에 비해 느리게 비우면), 그럼 send한 측에서는 SendBufferSize만큼 누적되다가 이후에는 메모리에 쌓이게 되는 것입니다.

------------------

일단 원칙은 그렇고요, Syong 님의 덧글에 따르면 비동기로 한 경우에는 SendCallback이 안 찍히고, 동기 send한 경우에는 모든 것이 정상적으로 돌아갔다는 건데요... 음... ^^; 이론상 이것은 맞지 않는 동작입니다. 2가지 경우 모두 서버에서 receive를 해주고 있는 상황이라면 모두 정상적으로 동작해야 합니다. (혹시 간단하게 재현되는 예제가 있으면 첨부해주세요.)

이 부분에 대해 설명할 수 있는 차이점을 발견하셔야 합니다. ^^;

------------------

두 번째 질문은 위에서 설명한 것과 이어지는데요, (동기든 비동기든) send가 된 것은 SendBuffer에 추가되었을 때 반환(또는 callback)이 됩니다. 그러니까, 그게 확실히 전송된 것과는 무관합니다. 왜냐하면 send buffer에 쌓인 후, 서버 측에서 receive를 하지 않았거나, 아니면 그 사이에 네트워크가 끊기면 그냥 그걸로 끝입니다. (TCP의 안정성은, 양 끝단이 살아 있을 때 버퍼의 내용을 모두 보내준다는 것을 보증하는 정도입니다.)

"확실"한 것을 어느 수준으로 정해야 하는 문제가 있는데요, 만약 "확실함"의 기준이 send 후 서버에서 해당 패킷이 처리되었다는 지점까지 원한다면 callback만으로는 부족합니다.

관련해서는 다음의 글도 한번 읽어보세요.

Wireshark + C#으로 확인하는 ReceiveBufferSize(SO_RCVBUF), SendBufferSize(SO_SNDBUF)
; https://www.sysnet.pe.kr/2/0/12532
정성태
2023-03-20 04시40분
[Syong] 결국은 일정하게 재현도 안되고, 24시간 운영하는 설비들에서 불규칙하게 1~5일이 지나면 동일 증상이 발생해서...
C++로 Winsock core만 작성해서 C++/CLI로 랩핑한 걸 C#에서 사용하는 방안으로 해결 아닌 해결을 해서 운영하고 있네요 ㅠ
[guest]
2023-03-20 06시15분
아쉬운 결과군요. 그래도 어쨌든 제품을 안정적으로 만드셨으니 다행입니다. ^^
정성태

1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
5832김지우2/21/20232916event와 delegate의 차이 , event를 써야하는 이유 [1]
5831이우람2/20/20233146ref 전역변수가 pinned가 될수 있나요? [2]
5830냉수마찰2/19/20233439C# GridView에 Column별 데이터 추가하는 방법에 대해 [1]
5829수박942/19/20233436키움 API를 윈폼과 WPF의 네임스페이스 없이 콘솔이나 WinUI3에서 사용할 수 있는 방법이 있나요? [2]파일 다운로드1
5828김재영2/19/20233227장기적으로는 this 구문을 안쓰는게 맞을까요? [2]
5827lee2/18/20233157파이썬 설치 오류 질문입니다 [1]
5826Syong2/14/20233732Socket 관련 Leak (OverlappedAsyncResult, OverlappedData) 관련 문의 [7]파일 다운로드1
5825박성원2/14/20233296Listview 컨트롤의 화면 전환 시 갱신 속도 [1]
5823검은콩2/13/20233899catch(Exception ex)의 line번호를 쉽게 알 수 없는지요? [7]
5822김지우2/11/20233161책을 보면서 sync, async 이해가 되지 않는 부분이 있습니다. [5]파일 다운로드2
5821검은콩2/9/20233179Async 신뢰성과 소켓데이터 [4]
5820차가워2/8/20233267다른 프로세스 실행 후 포커스 가져오기 [3]
5819취준생2/7/20233380WPF 관련 실무가 궁금합니다. [3]
5818윤길2/7/20232834ObservableCollection 에서 INotifyPropertyChanged 구현해야하나요? [2]
5817흰털너부리2/7/20232969배포 시 winform 실행 콘솔로그 보는 방법 [1]
5816흰털너부리2/6/20232784.net core json array validation 질문 드립니다. [1]
5815김재영2/6/20232908종단간 암호화에 대해 시나리오인데 타당한 시나리오일까요? [2]
5814한예지 donator2/6/20233260decompile? [9]
5813김재영2/5/20233150openssl genrsa 2048시 키 생성이 다르게 됩니다. - 파일첨부 [4]파일 다운로드1
5812김재영2/5/20233410openssl genrsa 2048시 키 생성이 다르게 됩니다. [2]
5811치르바2/3/20233238MiniDumpWriteDump API로 덤프수집을 했는데요.. [3]
5810이건우1/31/20233355윈도우서비스를 통한 웹통신관련 질문입니다 [3]
5809이상훈1/31/20233780다채널 영상 디스플레이어 개발 관련 질문입니다. [3]
5808근우1/30/20233453WPF 에서 UserControl 과 ControlTemplate 의 차이점은 무엇인가요? [6]
5807궁금맨1/28/20234616C# 10 책에 나온 예제의 결과가 제 컴에서는 좀 달라서요. 이유가 궁금합니다. [1]
5806스레드1/25/20233142총정리 - 다양한 스레드들 [초안] [1]파일 다운로드1
1  2  3  4  [5]  6  7  8  9  10  11  12  13  14  15  ...