블로그 이미지
.NETer

calendar

1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

Notice


Visual Studio 에서 프로세스를 이용한 디버깅 시 "'dbo' 소유자,'master '데이터베이스,'sp_sdidebug' 개체에 대한 EXECUTE 사용권한이 거부되었습니다." 와 같은 에러 메시지를 본다면 Visual Studio 프로세스 디버깅 시 아래와 같은 작업을 한다.

1. Visual Studio 2005 / 2008 도구 메뉴 혹은 디버그 메뉴에서 "프로세스에 연결"을 실행 하면 아래와 같은 그림을 볼 수 있다.


2. 위의 그림에서 "선택" 버튼을 클릭 하면 아래와 같은 그림을 볼 수 있다.


3. "다음 코드 형식 디버깅"을 선택 한 후 "관리", '네이티브"를 선택 하고 확인 버튼을 클릭 한 후 프로세스 연결을 하면 위와 같은 에러가 나지 않을 것이다.


이 에러의 경우 현재 데이터베이스에 접근 하는 사용자가 master 데이터베이스의 Stroed Procedure 를 실행할 권한이 없어서 발생하는 문제로 보인다. 보통의 경우 master 데이터베이스의 SP를 수행 할 수 있겠지만, 데이터베이스 권한을 따로 관리 하는 DBA가 존재 하다면 위와 같은 문제를 발생할 소지가 분명이 있다. 꼭 T-SQL를 Visual Studio 2005 / 2008 레벨에서 디버깅을 해야 한다고 하면 DBA를 설득 시켜야 겠지만 보통의 경우는 Visual Studio 2005 / 2008에서 T-SQL를 디버깅 하는 일이 거의 없을 것이다.


2009년 3월 9일 거의 두달 만이군 --> 다시 심기일전!!! 너무 바쁜 생활 ㅠㅠ .NETer

posted by .NETer
2008. 12. 17. 17:32 Reflection .NET/Troubleshooting

근래 들어 .NET Application에 대한 튜닝을 많이 하는 거 같다. 튜닝은 해결이 되면 재미 있지만 그 사이의 과정은 정말 피 말리는 싸움이다. 이번에는 .NET Application에서 Memory Leak이 발생하거나 혹은 Application Hang이 발생하는 이유를 쉽게 찾을 수 있는 방법을 소개 하도록 하겠다. 사실 이 부분은 전적으로 개인적인 의견이다. 이것이 절대 적이라고 볼 수는 없고 순전히 본인 경험치로 볼 수 있다.

모든 문제를 해결하고 난 이후 원인을 살펴 보면 프로그래밍을 할 때의 표준을 얼마나 잘 지키면서 코딩을 했느냐, 혹은 운영체제에 설치된 Application의 상황이 어떻게 되느냐에 따라 Memory Leak 발생할 수 있고, Application Hang이 발생할 수 있는 것이다. 현재 .NET Framework 2.0 이상 버전을 100% 신뢰할 수 없지만 많이 안정화 되었기 때문에 거의 모든 문제의 원인은 .NET Framework 코딩 패턴(COM+, Thread, File, Stream, Socket 등)을 사용하지 않거나 관리되지 않는 메모리 영역의 자원 해제, 혹은 운영 시스템에 설치된 다른 Application의 영향, 시스템 파라메터 수정 등이 원인이 될 수 있다.

 

자 그럼 .NET Application을 모니터링 할 수 있는 툴을 먼저 살펴 보자.

현재 .NET Application을 모니터링 할 수 있는 방법은 상용 툴 Quest 사의 Foglight for .NET 이나 마이크로소프트사에서 제공하는 .NET Profiler 등을 이용해 모니터링이 가능하다. Quest의 Foglight for .NET의 경우는 기능이 좋고 성능에도 많은 영향을 미치지 않고 .NET Application을 모니터링 하고 문제가 발생할 때 Alter을 할 수 있는 기능을 가지고 있지만 고가의 소프트웨어이기 때문에 쉽게 도입하거나 사용할 수 없을 것이다. MS사의 .NET Profiler로 모니터링을 할 수 있지만 개발 단계에서 하는 것은 가능 하지만 운영 시에 모니터링을 하기에는 너무 힘들기 때문에 배제를 하겠다. 그러던 중에 http://technet.microsoft.com/en-us/sysinternals/default.aspx 사이트에서 (예전에 http://www.sysinternals.com) 제공하는 Process Explorer(http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx) 가 눈에 띠어 사용해 보니 운영 중에 프로세스를 모니터링 하기에는 적합한 솔루션으로 보인다. 이 툴을 기준으로 .NET Application의 Memory Leak, Application Hang이 발생할 때 어떤 현상이 발생하고 그에 따른 코딩이 어떤 부분이 잘못 되었는지를 추론해 보자.

이 툴의 장점 중에 하나가 .NET Application의 상태를 확인 할 수 있다. 어떤 Handle을 사용하고 Thread 개수는 어떻게 되고 현재 사용하는 메모리, TCP/IP, .NET Counter의 값 등을 쉽게 확인 할 수 있다.

 

위의 그림에서 보는 것처럼 Process를 선택 하면 하단에 해당 프로세스가 사용하는 Handle을 볼 수 있고, 해당 프로세스의 속성을 열면 해당 프로세스의 상세한 내용을 확인 할 수 있다. 위의 그림의 경우 .NET Application을 선택 하였을 경우 볼 수 있는 속성 창으로 상세한 정보를 확인 할 수 있다. 여기서 Application이 잘못 되고 있는지를 확인할 수 있는 가장 손 쉬운 방법이 "Performance" 탭의 내용 중에 "Handles"의 값을 보면 알 수 있다. 이 값의 경우 Windows의 작업 관리자에서도 확인 할 수 있지만 실제 어떤 handle이 늘어 나고 있는지는 확인 할 수 없기 때문에 이 툴을 사용하는 것이다. 만일 핸들이 주체 할 수 없을 정도로 늘어나기 시작하면 시스템에 부하를 주게 된다. 핸들은 결국 하나의 Application이 사용하고 있는 메모리 집합, Working의 집합이라고 할 수 있다. 자 그럼 Handle의 종류와 그 의미를 알아 보도록 하겠다. 여기 기입 하는 내용은 전적으로 내 개인적인 생각을 적은 것이다. 예전에 운영체제 시간에 배운 내용과 협업에서 일하면서 터득한 내용으로 정확하지 않다.

Handle Type

설명

Desktop

내부적으로 사용하는 기본 핸들로 보인다.

Directory

내부적으로 사용하는 기본 핸들로 보인다.

Event

코딩 시 Event가 발생하는 케이스에 늘어나는 핸들이다. .NET의 경우 Event 처리에 대한 모든 것이 이 핸들로 등록 된다. 이벤트가 발생할 때 마다 하나의 핸들이 늘어나게 된다.

File

해당 Application에서 파일을 읽거나 쓰거나 참조 하거나 할 때 늘어나는 핸들이다. TCP, Device의 경우도 다 파일 핸들에 포함된다.

Key

참조하는 레지스트리 값의 핸들이다.

KeyedEvent

내부적으로 사용하는 기본 핸들로 보인다.

Mutant

프로세스간 동기화를 위한 Mutex 관련 핸들이다.

Port

내부적으로 사용하는 기본 핸들로 보인다.

Process

프로세스 번호 핸들이다.

Section

내부적으로 사용하는 기본 핸들로 보인다.

Semaphore

프로세스간 동기화를 위한 Semaphore 관련 핸들이다.

Thread

현재 Process가 가지고 있는 Thread 핸들이다. 우리가 Thread 처리를 할 경우 발생하는 핸들이다.

Token

인증에 관련된 핸들로 COM+와도 연관이 있는 핸들이다.

WindowStation

내부적으로 사용하는 기본 핸들로 보인다.

 

여기서 주의해서 봐야 할 것이 Event, File, Thread, Token 정도 일 것이다. 지금까지 대 부분의 경우 문제를 발생하면 4가지 핸들 중에 한 놈이 범인이다. 그 원인만 파악 하면 대충 어디 부분이 잘못 됐는지를 짐작 할 수 있다.

  1. Event Handle : .NET에서 프로그래밍 할 경우 Delegate 또는 Event 처리 등의 코딩 패턴에서 발생하는 핸들로 이 것이 늘어 나게 되면 메모리의 증가를 나타나게 된다. 예를 들어 Mcafee 같은 백신의 경우 파일이 작성되거나 변경 되거나 할 경우 간섭을 하는 경우가 발생한다. 어떤 특정 이벤트에서 파일을 핸들링 하게 되면 이 백신의 간섭으로 Event 핸들이 일을 종료 한 후 빠지는 것보다 더 많은 핸들이 유입되 메모리가 기하 급수로 늘어나고 결국 시스템이 멈추는 현상이 발생할 수 있다. 마찬 가지로 코딩 시 Event에 대한 처리를 제대로 하지 않았을 경우도 Event가 늘어만 나고 줄어 들지 않을 수 있다.
  2. File Handle : Process가 핸들링하는 파일의 개수가 많이 지면 파일 핸들이 늘어나게 된다. 보통의 경우는 특별히 문제가 되지 않을 것이다. 이 부분은 대 부분의 경우 시스템이 사용하는 파일에 대한 정보를 볼 수 있고, 또한 Application내에서 핸들링하는 파일을 볼 수 있다. Stream 을 핸들링 할 경우는 꼭 .NET 코딩 패턴에 따란 Stream.close(), Stream.Dispose()를 하기 바란다.
  3. Thread Handle : 하나의 Process는 여러 개의 Thread로 나뉘어서 동작 하게 된다. 대 부분의 경우 .NET Framework에서 사용하는 Thread의 핸들이 늘어나겠지만, Application 내부에서 사용한 Thread 클래스를 통해 핸들이 증가 할 수 있다. 당연 Thread 작업 시는 주의를 해야 한다. 이 부분 때문에 Application이 비정상 종료 될 수 있기 때문이다.
  4. Token Handle : 얼마전에 확인한 부분인데 COM+ 코딩 시 Class의 Attribute의 JustInTimeActivation Attribute 및 Method의 Attribute인 AutoComplete Attribute를 패턴대로 코딩을 하지 않고 분산 트랜잭션에 태우게 되면 Token의 핸들은 계속 늘어나고 없어지지 않게 되 결국 Process가 비 정상 종료 되는 경우를 확인 할 수 있었다. COM+가 Token 핸들을 사용하는 것으로 보인다. 아마도 AutoComplete 관련된 부분이 Token과 관련 되어 보인다.

핸들의 경우 아래 블로그를 참조 하면 시스템 상에서 Application 핸들 제한을 어떻게 할 수 있는지를 확인 할 수 있다.

http://winlife.tistory.com/trackback/38

http://2diku.com/tt/orz/trackback/7

 

대부분의 경우 Handle로만 해결이 가능하겠지만 현재 Application이 안정적으로 돌고 있는지를 확인 할 수 있는 것은 프로세스 속성 창의 ".NET" 탭을 보면 현재 프로세스가 사용하고 있는 .NET의 값을 확인 할 수 있다. Data, Exception, Interop, Jit, Loading, Memory 등을 확인 할 수 있다. 여기서 주의해서 봐야 할 부분은 Memory일 것이다.

메모리의 경우 GC 상황을 보면 개발 시 IDisposable 인터페이스를 상속받아 구현한 클래스를 Dispose() 메소드를 강제로 수행하지 않아 계속 GC영역에 남게 되고 이게 늘어나면 성능에도 문제가 발생할 소지가 있다.

 

다른 부분의 경우 실제 모니터링을 해보면 .NET Application이 어떻게 돌아가는지 이해를 할 수 있을 것이다.

 

2008년 12월 17일 성능 튜닝을 하면서 .NETer

posted by .NETer
prev 1 next