Microsoft MVP성태의 닷넷 이야기
Socket 관련 Leak (OverlappedAsyncResult, OverlappedData) 관련 문의 [링크 복사], [링크+제목 복사],
조회: 4002
글쓴 사람
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분
아쉬운 결과군요. 그래도 어쨌든 제품을 안정적으로 만드셨으니 다행입니다. ^^
정성태

... 31  32  33  34  35  36  37  38  39  40  41  42  43  44  [45]  ...
NoWriterDateCnt.TitleFile(s)
4722지나가던...5/15/201614744Part 3 pdf파일 그림 재수정 문의 [1]
4723지나가던...5/16/201611983    답변글 [답변]: Part 3 pdf파일 그림 재수정 문의 [1]
4721김종희4/30/2016121173D 시뮬레이션 개발 [1]
4720DC4/29/201611467C# 6.0 델리게이트 인스턴스화 관련 질문~ [2]
4719이민구4/29/201612374[시작하세요! C# 프로그래밍] 4.5.1.6 열거형 마지막 예제 질문입니다. [4]파일 다운로드1
4718ds4/27/201610568오라클 DB 칼럼에 있는 특정 데이터를 가져올수가 있나여? [1]
4717최령진4/26/20169714모바일 웹 앱 관련문의 드립니다 [1]
4715과객4/7/201611748TFS 와 Stylecop Integration 시 체크인 정책 적용 방법이 궁금합니다. [1]
4714임형복4/7/201611708DLL 을 프로세스처럼 사용하기 [3]파일 다운로드1
4713김태훈4/5/201611912하위 폴더 권한 상속 문제 [1]
4712차가워4/5/201613554멀티코어 스레드 문의 [1]
4711이대희4/1/201611125Xamarin 라이센스 변경 (Visual Sutuio 무료 사용) [2]
4709가가멜3/25/201635599국내 WPF 책은 왜 2010 년 이후로 전멸인지요? [1]
4704최훈3/15/201615440C# 6.0 예제 7.1 관련 질문입니다. [2]
4702popo3/14/201614907C# WeakReference이 CPU 플랫폼 설정 마다 결과가 틀리게 나옵니다. [9]
4701쌉쓰릅3/13/201612614uwp에서 그림판의 지우개 기능을 구현하려고하는데요 참고할 만한 정보가 있을가요? [2]
4700정우진3/12/201611022안녕하세요. 10049소켓에러의 해결법을 알고싶습니다. - 수정본 [1]파일 다운로드1
4699정우진3/11/201613840안녕하세요. 10049소켓에러의 해결법을 알고싶습니다. [1]
4698지나가는3/10/201612458안녕하세요. 주기적으로 일어나는 .net 관련 질문이 있습니다 [1]
4697정우진3/9/201610084안녕하세요. AWS EC2를 이용한 서버 개발에 대해 질문드립니다. [1]
4696삽질맨3/9/201614668Winform Cold Start 로딩 속도 개선 방법이 없을까요? [1]
4695popo3/9/201612332wpf의 ICommand 질문 입니다. [5]파일 다운로드1
4694아무개2/28/201611940책 잘보고있습니다~ [1]
4693초보2/25/201610143카카오톡 오류 질문 [1]
3701강준2/19/2016195692개의 DataTable Join 결과 전체 컬럼을 DataTable 로 리턴하기 [5]
3700박성훈2/18/201611294시작하세요! C# 6.0 프로그래밍 105쪽 예제 질문 [1]
... 31  32  33  34  35  36  37  38  39  40  41  42  43  44  [45]  ...