Microsoft MVP성태의 닷넷 이야기
Socket 관련 Leak (OverlappedAsyncResult, OverlappedData) 관련 문의 [링크 복사], [링크+제목 복사]
조회: 3620
글쓴 사람
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)
5906guest4/21/20233371Dispatcher 서비스 구현 질문 [1]
5905guest4/20/20233669tabControl의 tabPage가 여러 개일 때 순서를 바꾸기가 까다롭네요 [5]
5904guest4/18/20233603[신규자료첨부] DLL 'SQLite.Interop.dll'을 찾을 수 없습니다 [4]파일 다운로드1
5903guest4/18/20233078fileSystemWatcher 이벤트 관련 질문입니다 [2]
5902guest4/17/20233684c#으로 USB 관련 질문 [2]
5901guest4/17/20233271내솔루션 판매 시 1.0.0.0 폴더와 Sqlite 배포 [5]
5900guest4/17/20234436DLL 'SQLite.Interop.dll'을 찾을 수 없습니다 [2]파일 다운로드1
5899guest4/17/20233378Dictionary와 Linq [4]
5898차가워4/17/20233188CNTK 교육 문의 [1]
5897guest4/17/20233124Socket스레드와 UI thread [4]
5896HAN4/16/20233099c언어 return 에 대해 궁금한게 있어요. [1]파일 다운로드1
5895guest4/15/20232858Drag and Drop - 모든 컨트롤 [2]
5894송부장4/14/20234258[질문] Visual Studio 2022에서 '도구 상자 항목 선택'의 'COM 구성 요소' 탭에서 ActiveX 목록이 보이지 않습니다. [3]파일 다운로드2
5893감사합니...4/14/20232895오라클 OLEDB방식 접속 후 SELECT 'TEST' TEST_VALUE FROM DUAL의 값이 이상합니다. [1]
5892한무4/14/20233088C# 으로 백그라운드에서 워드를 실행하여 매크로 실행이 가능 할까요? [2]
5891리세4/14/20232974안녕하세요.C# 서버프로그램에서의 Mysql 쿼리문제(다중쿼리 실행)에 대해 문의드립니다. [2]
5890guest4/14/20233603C# 프리랜서로 돈 벌려면 성태님 책 마스터하면 되나요? [6]
5889전예찬4/14/20232811C# 파일 복사 관련 질문 드립니다. [3]
5888정경구4/12/20233085C# 첫 환경 세팅과 관련해서 [4]
5887HAN4/12/20232724안녕하세요 파이썬도 공유 가능 할까요? [1]
5886guest4/11/20233110필요한 어셈블리만 다운로드 및 재로딩하는 방법에 관하여 [2]
5885guest4/11/20232978c#으로 드림위버같은 거 만들어볼려는데요 [6]
5884궁금이4/11/20232857부모 클래스에서 예외 발생시 힙 영역에 할당 ? [2]
5883코딩초짜4/9/2023273810c언어 usleep 에 대해서 요 [2]
5882조은현4/7/20232809선생님 안녕하세요! wpf의 성능 개선에 대해서 질문드려요! [1]파일 다운로드1
5881guest4/6/20232926static method - <에러메시지 Extension method must be defined in a non-generic static class> [4]
1  [2]  3  4  5  6  7  8  9  10  11  12  13  14  15  ...