비동기 프로그래밍에서의 메모리 누수

Posted in .NET Framework // Posted at 2013. 11. 6. 11:24
728x90

응용프로그램의 성능, 확장성 향상의 이유로 비동기 프로그래밍 방식이 자주 사용되곤 한다.

 

닷넷 프레임워크에서도 스레드(전용 스레드 or 스레드 풀) 혹은 비동기 프로그래밍 모델을 활용해 비동기 작업을 수행할 수 있다.

 

여기서 비동기 프로그래밍 모델을 APM(Asynchronous Programming Model)이라 칭하는데, 닷넷 프레임워크의 I/O 관련 클래스들은 모두 이 모델을 이용할 수 있도록 설계되어 있다.

 

 

I/O를 위한 동기 방식 메서드 이름과 동일한 BeginXXX, EndXXX 쌍의 비동기 메서드가 제공되는데, 다음과 같은 I/O 클래스들에서 이를 활용할 수 있다.

 

System.Net.WebRequest

System.IO.Stream

System.Data.SqlClient.SqlCommand

System.Net.Sockets.Socket

 

필자의 회사에서 운영하는 시스템도 많은 곳에시 비동기 패턴을 이용하고 있다. 그 중 한 예로, 여러 시스템이 혼재되어 하나의 서비스를 완성하는데 이때 각 시스템의 구간 안정성 현황을 파악하기 위해 원격 서버로 로그를 전송하는 로직이 비동기로 구현되어 있다.

 

그런데 이 로그는 실제 비지니스와는 무관한 부분이라(크로스 커팅 기능), 종속성을 배제하기 위해 로그 서버는 단방향 서비스로 구현하고 이를 소비하는 클라이언트는 APM 방식으로 구현되어 있다.

 

그런데 문제는 로그 저장의 성공/실패에 관심을 두지 않는다는 것이, 비동기 호출 후 콜백을 받지 않는 구현으로 이어졌다는 것이다. 즉 BeginXXX만 호출하고 EndXXX는 구현하지 않은 것이다.

 

사용량이 많지 않는 환경에서는 이것이 그리 큰 문제가 되지는 않는다. 하지만 필자의 시스템 환경은 Server to Server 방식으로 로그서버를 소비하는 클라이언트 역시 서버 응용프로그램이며 이 서버 응용프로그램에 수많은 요청이 동시에 몰리면 메모리 누수는 점차 누적되어 프로그램이 심각한 타격을 입을 수 있다는 것이다.

 

다음의 글에서 밝히고 있듯이, 비동기 호출 결과에 관심이 없다고 해서 EndXXX를 호출하지 않아도 된다는 것은 아니니 주의해야 할 일이다.

 

개발자는 EndXXX 메서드를 꼭 호출해야 한다. 그렇지 않으면 리소스가 누수되기 때문이다. 일부 개발자는 데이터 장치에 자료를 저장하기 위해서 BeginXXX를 호출하고, 이후의 결과 값이나 진행 상태에 관심이 없다면 EndXXX를 호출하지 않는 경우를 종종 봐왔다. 하지만 EndXXX를 호출해야 하는 이유는 두 가지가 있다.

 

첫째 CLR은 이 리소스들을 EndXXX 메서드가 호출될 때까지 유지시킨다. 그리고 EndXXX 메서드가 결국 호출되지 않는다면 이 리소스들은 계속 반환되지 않다가 프로세스가 종료될 때에 반환된다. 둘째, 비동기 작업을 초기화할 때 실제로 개발자는이 작업이 성공할 것인지 알지 못한다. 성공유무를 확실하게 확인하는 방법은 EndXXX 메서드를 호출하는 것이며, 이 메서드를 호출함으로써 결과 값이 정상적으로 반환되는지 아니면 예외가 발생하는지 알 수 있다.

- CLR via C#

 

 

'.NET Framework' 카테고리의 다른 글

Optimizing IIS Performance  (8) 2013.11.07
클라이언트의 동시 연결 수(maxconnection)  (6) 2013.11.06
OAuth 2.0 Flow  (6) 2013.09.05
Custom Configuration  (2175) 2013.08.26
간단한 C# 문법 Quiz  (5) 2013.07.11