Microsoft MVP성태의 닷넷 이야기
.NET Framework: 688. NGen 모듈과 .NET Profiler [링크 복사], [링크+제목 복사],
조회: 25078
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)
(시리즈 글이 11개 있습니다.)
.NET Framework: 177. .NET 2.0 Profiler에 .NET 4.0 지원 추가
; https://www.sysnet.pe.kr/2/0/861

.NET Framework: 216. 라이선스까지도 뛰어넘는 .NET Profiler
; https://www.sysnet.pe.kr/2/0/1046

.NET Framework: 336. .NET Profiler가 COM 개체일까?
; https://www.sysnet.pe.kr/2/0/1352

.NET Framework: 576. 기본적인 CLR Profiler 소스 코드 설명
; https://www.sysnet.pe.kr/2/0/10950

.NET Framework: 582. CLR Profiler - 별도 정의한 .NET 코드를 호출하도록 IL 코드 변경
; https://www.sysnet.pe.kr/2/0/10959

.NET Framework: 688. NGen 모듈과 .NET Profiler
; https://www.sysnet.pe.kr/2/0/11321

.NET Framework: 808. .NET Profiler - GAC 모듈에서 GAC 비-등록 모듈을 참조하는 경우의 문제
; https://www.sysnet.pe.kr/2/0/11810

오류 유형: 672. AllowPartiallyTrustedCallers 특성이 적용된 어셈블리의 struct 멤버 메서드를 재정의하면 System.Security.VerificationException 예외 발생
; https://www.sysnet.pe.kr/2/0/12384

.NET Framework: 987. .NET Profiler - FunctionID와 연관된 ClassID를 구할 수 없는 문제
; https://www.sysnet.pe.kr/2/0/12465

.NET Framework: 1041. C# - AssemblyID, ModuleID를 관리 코드에서 구하는 방법
; https://www.sysnet.pe.kr/2/0/12605

닷넷: 2228. .NET Profiler - IMetaDataEmit2::DefineMethodSpec 사용법
; https://www.sysnet.pe.kr/2/0/13576




NGen 모듈과 .NET Profiler

테스트를 위해 다음과 같이 현재 프로세스에 올라온 NGen 이미지 목록을 출력하는 프로그램을 만들어 봅니다.

using System;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {
        // How to determine if assembly has been ngen'd?
        // https://stackoverflow.com/questions/2167382/how-to-determine-if-assembly-has-been-ngend
        static void Main(string[] args)
        {
            Console.WriteLine("Is64bit == " + Environment.Is64BitProcess);

            Process process = Process.GetCurrentProcess();

            ProcessModule[] modules = new ProcessModule[process.Modules.Count];
            process.Modules.CopyTo(modules, 0);

            var niQuery = from m in modules where m.FileName.Contains(".ni.") select m.FileName;
            bool ni = niQuery.Count() > 0 ? true : false;

            if (ni == false)
            {
                return;
            }

            foreach (var item in niQuery)
            {
                Console.WriteLine("Native Image: " + item);
            }

            Console.WriteLine("press RETURN to exit...");
            Console.ReadLine();
        }
    }
}

빌드하고 실행하면 다음과 같은 출력 결과를 볼 수 있습니다.

D:\temp>ConsoleApp1.exe
Is64bit == True
Native Image: C:\Windows\assembly\NativeImages_v4.0.30319_64\mscorlib\701f2b79b02a02beba70e50bb2edb212\mscorlib.ni.dll
Native Image: C:\Windows\assembly\NativeImages_v4.0.30319_64\System\32e6872e37b1f771bbe543748e6e73f0\System.ni.dll
press RETURN to exit...

정상적으로 mscorlib.dll과 system.dll에 대해 ngen-ed 이미지가 올라온 것을 확인할 수 있습니다.

자, 그럼 해당 프로세스에 .NET Profiler를 붙여 봅니다. 이때의 프로파일러는 COR_PRF_USE_PROFILE_IMAGES 옵션을 사용하는 것이어야 합니다. 이제 다시 예제 프로그램을 실행하면 다음과 같은 출력 결과를 얻을 수 있습니다.

D:\temp>ConsoleApp1.exe
Is64bit == True
press RETURN to exit...

왜냐하면 (COR_PRF_USE_PROFILE_IMAGES 옵션을 적용한) .NET Profiler는 ngen-ed 이미지 중에서도 /profile 옵션이 적용된 ngen-ed 이미지만을 로드할 수 있기 때문입니다. 그렇지 않은 경우 무조건 원본 어셈블리로부터 JIT 시켜서 사용합니다.




COR_PRF_USE_PROFILE_IMAGES 옵션을 적용한 .NET Profiler가 ngen-ed 이미지를 사용할 수 있도록 만든 방안이 바로 /profile 옵션을 적용한 새로운 ngen-ed 이미지입니다.

C:\Windows\Microsoft.NET\Framework64\v4.0.30319>ngen install mscorlib.dll /profile
Microsoft (R) CLR Native Image Generator - Version 4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.
Installing assembly mscorlib.dll
    Compiling assembly mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 (CLR v2.0.50727) ...
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 <profiling>

C:\Windows\Microsoft.NET\Framework64\v4.0.30319>

이렇게 /profile 이미지를 마련해 주고 다시 COR_PRF_USE_PROFILE_IMAGES 옵션을 적용한 .NET Profiler를 실행시키면 ngen-ed 이미지들이 올라오는 것을 확인할 수 있습니다.

D:\temp>ConsoleApp1.exe
Is64bit == True
Native Image: C:\Windows\assembly\NativeImages_v4.0.30319_64\mscorlib\c94771552ff5ac0bc50c073bf5b71fb6\mscorlib.ni.dll
press RETURN to exit...

당연히 처음 실행과 비교해 ngen-ed 이미지들의 경로도 다릅니다.

// release 버전의 mscorlib.ni.dll
    C:\Windows\assembly\NativeImages_v4.0.30319_64\mscorlib\701f2b79b02a02beba70e50bb2edb212\mscorlib.ni.dll

// profiling 버전의 mscorlib.ni.dll
    C:\Windows\assembly\NativeImages_v4.0.30319_64\mscorlib\c94771552ff5ac0bc50c073bf5b71fb6\mscorlib.ni.dll




몇 가지 유용한 명령어를 미리 소개해 드리면, 우선 /profile 옵션이 적용된 어셈블리는 각 플랫폼/CLR 별로 해줘야 합니다. 그래서 원하는 어셈블리가 있다면 다음과 같이 실행하면 됩니다.

"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ngen" install d:\temp\test.dll /profile
"C:\Windows\Microsoft.NET\Framework64\v2.0.50727\ngen" install d:\temp\test.dll /profile
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\ngen" install d:\temp\test.dll /profile
"C:\Windows\Microsoft.NET\Framework\v2.0.50727\ngen" install d:\temp\test.dll /profile

또한 /profile로 생성하는 경우 대상 어셈블리뿐만 아니라 그것이 참조/의존하고 있는 모든 어셈블리들이 함께 /profile NGen 이미지들이 생성됩니다.

이후, /profile 옵션이 적용된 어셈블리 목록을 다음의 명령어로 간결하게 구할 수 있습니다.

ngen display | find "<profiling>"

재미있는 것은, ngen display는 플랫폼 단위로 CLR 버전에 상관없이 /profile 이미지들을 보여준다는 점입니다. 그래서 플랫폼 별로만 다음과 같이 확인하면 됩니다.

// CLR 2/4에 상관없이 64비트 /profile NGEN 이미지 목록을 출력
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ngen" display | find "<profiling>"

// CLR 2/4에 상관없이 32비트 /profile NGEN 이미지 목록을 출력
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\ngen" display | find "<profiling>"

/profile NGen 이미지들을 삭제하고 싶다면 다음의 명령어로 할 수 있습니다.

ngen uninstall * /profile

display 옵션과 마찬가지로 이것 역시 플랫폼 단위로 CLR 버전에 상관없이 적용됩니다. 따라서 각각의 플랫폼 별로 실행해야 전부 삭제됩니다.

// CLR 2/4에 상관없이 64비트 /profile NGEN 이미지를 삭제
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\ngen" uninstall * /profile

// CLR 2/4에 상관없이 32비트 /profile NGEN 이미지를 삭제
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\ngen" uninstall * /profile

만약 개별 어셈블리를 지정한다면 다음과 같이 어셈블리 이름 형식으로 삭제할 수 있습니다.

// 플랫폼에 등록된 test 프로파일 NGen 이미지를 CLR 버전에 상관없이 삭제
ngen uninstall test /profile

// 플랫폼에 등록된 "test, Version=2.3.0.0"에 해당하는 프로파일 NGen 이미지를 CLR 버전에 상관없이 삭제
ngen uninstall "test, Version=2.3.0.0" /profile




검색하다 보면, 일부 .NET Profiler 제품의 경우 profile NGEN 이미지들이 있는 경우 오동작을 한다는 글이 있습니다.

Known issues with "profile" NGEN Images
; https://dotnettools-support.jetbrains.com/hc/en-us/articles/207241935-Known-issues-with-profile-NGEN-Images

위의 글을 정리해 보면, "dotCover"나 "dotTrace"같은 제품의 경우 다음과 같은 예외가 발생한다고 합니다.

System.MissingMethodException: Method not found: 'Void System.Runtime.Versioning.TargetFrameworkAttribute.JetBrains_Profiler_Core_Instrumentation_Begin(UIntPtr ByRef)

개발자이다 보니 ^^ 문제의 원인이 눈에 들어옵니다.

위와 같은 제품들은 COR_PRF_USE_PROFILE_IMAGES 옵션을 사용하고 있으며 mscorlib.dll의 메서드까지도 injection할 수 있도록 mscorlib.dll에 이미 정의된 System.Runtime.Versioning.TargetFrameworkAttribute 타입에 JetBrains_Profiler_Core_Instrumentation_Begin 메서드를 "동적으로" 추가한 유형입니다.

따라서 /profile 이미지가 있는 경우 그 버전의 mscorlib.ni.dll을 로드하게 되고 당연히 "동적으로" JetBrains_Profiler_Core_Instrumentation_Begin 메서드를 TargetFrameworkAttribute 타입에 정의할 기회를 잃어버리는 것입니다. 그렇기 때문에 다른 메서드에 대한 IL 코드를 변조해 JetBrains_Profiler_Core_Instrumentation_Begin을 호출하도록 만들게 되면 System.MissingMethodException 예외가 발생합니다.

마이크로소프트 측에서 이에 대해 다음 버전에 플래그를 추가해 줄 거라고 하는데 아마도 그 플래그가 .NET 4.5부터 추가된 COR_PRF_DISABLE_ALL_NGEN_IMAGES일 것입니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 5/24/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




... 196  197  [198]  199  200  201  202 
NoWriterDateCnt.TitleFile(s)
139정성태11/14/200520461    답변글 .NET Framework: 26.1. ^^ 역시, 배려가 되어 있네요. 제가 못 찾은 것이었습니다.
104정성태2/27/200523320VS.NET IDE: 23. MSI 설치 중에 GetLocalTime / GetSystemTime API 사용
132정성태3/30/200522845    답변글 VS.NET IDE: 23.1. [추가]: MSI 설치 동작 원리
102정성태2/16/200525857.NET Framework: 25. Verify that you are a member of the 'Debugger Users' group on the server. [2]
101정성태2/15/200523771.NET Framework: 24. WMI Win32_NTLogEvent 관리 이벤트를 Windows 2000 에서는 "Access Denied" 가 발생하는 문제파일 다운로드1
100정성태2/15/200529872VS.NET IDE: 22. 방화벽 환경에서의 WMI 연결을 위한 포트 설정 [2]
99정성태2/15/200528036COM 개체 관련: 13. 비동기 Drag & Drop 구현 : IAsyncOperation
103정성태2/23/200523862    답변글 COM 개체 관련: 13.1. [관련 자료] 그외 Drag & Drop 링크파일 다운로드1
97정성태2/14/200526813VS.NET IDE: 21. 설치된 Platform SDK 버전확인 방법
96정성태2/14/200528577기타: 9. http://www.google.com/webhp?complete=1&hl=en 검색에 관해서.
95정성태2/14/200538174VS.NET IDE: 20. Win32 특권 정리 [1]
94정성태1/29/200529256VC++: 13. VS.NET 2005 VC++ 컴파일러 에러 : cannot instantiate abstract class
93정성태1/29/200524997VS.NET IDE: 19. 혹시 VS.NET 2005 Beta2(2004/12 CTP Team System 버전)이 다운이 자주 되나요? [2]
92정성태1/29/200523502.NET Framework: 23. Unmanaged 환경에서 Managed DLL에 정의된 메서드 호출 시 오류 확인하는 방법
91정성태11/14/200524234VC++: 12. VS.NET 2005 VC++ Debug: Expression: ( (state != ST_INVALID ) )
90정성태1/27/200525294.NET Framework: 22. Debug: The underlying connection was closed: Unable to connect to the remote server.
89정성태1/26/200529637VC++: 11. Delay Loaded DLL
87정성태1/23/200523424VS.NET IDE: 18. VS.NET 2005 Beta 1 - VC++ 프로젝트에서 Connection Point 구현시 버그
88정성태1/23/200522768    답변글 VS.NET IDE: 18.1. VS.NET 2003 : VC++ 프로젝트에서 Connection Point 추가시에도 버그
86정성태1/23/200528648.NET Framework: 21. Code Snippet - Enum과 관련된 다양한 형변환 [1]
85정성태1/23/200526870스크립트: 4. Windows 2003에서 BHO(Browser Helper Objects) 동작 안하는 현상 [1]
83정성태1/18/200532455.NET Framework: 20. System.AccessViolationException 예외가 발생한 한 예.
82정성태1/3/200525682VS.NET IDE: 17. Windows 운영 - 특정 사용자 또는 그룹에 대해서 파일 공유 접근 금지
79정성태1/20/200533391기타: 8. DELL Latitude D800 노트북 컴퓨터의 PC Beep 소음(!) 문제.
78정성태12/27/200425710VS.NET IDE: 16. MS 제품 관련 사용되는 TCP/IP 포트 열거파일 다운로드1
77정성태12/27/200425986VS.NET IDE: 15. Virtual CD-ROM Control Panel - ISO 이미지를 CD-ROM 드라이브처럼 접근하게 해주는 EXE 프로그램 [1]파일 다운로드1
... 196  197  [198]  199  200  201  202