성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
[정성태] 저렇게 조각 코드 말고, 실제로 재현이 되는 예제 프로젝트를 압...
[정성태] Modules 창(Ctrl+Shift+U)을 띄워서, 해당 Op...
[정성태] 만드실 수 있습니다. 단지, Unity 엔진 내의 스크립트와 W...
[공진영] 안녕하세요 좋은글 감사합니다. 현재 제가 wpf로 관제 모...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>CLR Profiler로 살펴보는 SharedDomain의 모듈 로드 동작</h1> <p> 지난 글에서 SharedDomain과 기타 AppDomain들에 로드된 모듈의 상황을 살펴봤는데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > .NET - 눈으로 확인하는 SharedDomain의 동작 방식 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/10948'>http://www.sysnet.pe.kr/2/0/10948</a> </pre> <br /> 이번에는 모듈의 로드가 CLR Profiler의 콜백 함수에 어떤 동작을 야기시키는지 살펴보겠습니다.<br /> <br /> 일단, 이번 글에서 쓸 예제 코드는 다음의 글에 포함된 것을 그대로 재사용합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > SharedDomain과 JIT 컴파일 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/10949'>http://www.sysnet.pe.kr/2/0/10949</a> </pre> <br /> 그리고 CLR Profiler의 소스 코드는 다음의 것을 그대로 가져다가,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 기본적인 CLR Profiler 소스 코드 설명 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/10950'>http://www.sysnet.pe.kr/2/0/10950</a> </pre> <br /> 출력 코드만 OutputDebugText에서 wprintf로 바꿔 재사용할 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > HRESULT CBasicClrProfiler::ModuleLoadFinished(ModuleID moduleId, HRESULT hrStatus) { ULONG cchModule = _MAX_PATH; ULONG rCchModule = 0; AssemblyID assemblyId = 0; LPCBYTE pModuleBaseLoadAddress; wchar_t szModule[_MAX_PATH]; HRESULT hr = m_pICorProfilerInfo2->GetModuleInfo(moduleId, &pModuleBaseLoadAddress, cchModule, &rCchModule, szModule, &assemblyId); wprintf(L"%s loaded at 0x%x, ModuleID = 0x%x\n", szModule, pModuleBaseLoadAddress, moduleId); return S_OK; } </pre> <br /> 준비 작업은 모두 끝났군요. 이제 Main 메서드에 부여된 LoaderOptimization 값만 바꿔가면서 각각의 상황을 테스트해보면 됩니다. 아래는 그 결과를 정리한 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ================ LoaderOptimization.SingleDomain <span style='color: blue; font-weight: bold'>C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll loaded at 0x42d0000, ModuleID = 0x42d1000 C:\shareddomain_clrprof\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe loaded at 0xaf860000, ModuleID = 0xb70140c0 C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll loaded at 0xafaa0000, ModuleID = 0xb7015b80 C:\shareddomain_clrprof\ConsoleApplication1\bin\Debug\WeakDLL.dll loaded at 0xafc40000, ModuleID = 0xb70163e8 C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll loaded at 0xb520000, ModuleID = 0xb521000</span> StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7120820 WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7120b90 <span style='color: blue; font-weight: bold'>C:\shareddomain_clrprof\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe loaded at 0xaf860000, ModuleID = 0xb7175308 C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll loaded at 0xafaa0000, ModuleID = 0xb7175c88 C:\shareddomain_clrprof\ConsoleApplication1\bin\Debug\WeakDLL.dll loaded at 0xafc40000, ModuleID = 0xb71764f0</span> StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7190630 WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab71909a0 </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ================ LoaderOptimization.MultiDomainHost <span style='color: blue; font-weight: bold'>C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll loaded at 0x42d0000, ModuleID = 0x42d1000 C:\...\shareddomain_clrprof\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe loaded at 0xdef90000, ModuleID = 0xb70340c0 C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll loaded at 0xdf2c0000,ModuleID = 0xb7024780 C:\...\shareddomain_clrprof\ConsoleApplication1\bin\Debug\WeakDLL.dll loaded at 0xdf300000, ModuleID = 0xb7035cb8 C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll loaded at 0xb520000, ModuleID = 0xb521000</span> StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7140c30 WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7140f90 <span style='color: blue; font-weight: bold'>C:\...\shareddomain_clrprof\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe loaded at 0xdef90000, ModuleID = 0xb7195308 C:\...\shareddomain_clrprof\ConsoleApplication1\bin\Debug\WeakDLL.dll loaded at 0xdf300000, ModuleID = 0xb7195dc0</span> StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7140c30 WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab71b0680 </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ================ LoaderOptimization.MultiDomain <span style='color: blue; font-weight: bold'>C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll loaded at 0x42d0000, ModuleID = 0x42d1000 C:\shareddomain_clrprof\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe loaded at 0xfe440000, ModuleID = 0xb7014178 C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll loaded at 0x989d0000, ModuleID = 0xb7014e98 C:\shareddomain_clrprof\ConsoleApplication1\bin\Debug\WeakDLL.dll loaded at 0x98a00000, ModuleID = 0xb70155b0 C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll loaded at 0xb520000, ModuleID = 0xb521000</span> StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7130780 WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7130a90 StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7130780 WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7130a90 </pre> <br /> 보시는 바와 같이, 결과는 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/10948'>.NET - 눈으로 확인하는 SharedDomain의 동작 방식</a>" 글과 동일합니다. 가령, 모든 어셈블리를 SharedDomain에 로드해 재사용하는 LoaderOptimization.MultiDomain 모드는, 최초의 AppDomain에서 로드된 경우 이후 생성되는 AppDomain에서는 ModuleLoaded 이벤트가 발생하지 않고 기존 모듈을 그대로 이용하는 것입니다.<br /> <br /> JIT 컴파일도 마저 확인을 해볼까요? DoMethod, Main 메서드가 실행되면 로그를 남기도록 CLR Profiler의 소스 코드를 다음과 같이 변경한 후,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #pragma once #include "resource.h" // main symbols #include "SampleProfiler_i.h" #include "ICorProfilerCallback3Impl.h" // ..[생략]... class ATL_NO_VTABLE CBasicClrProfiler : // ..[생략]... public ICorProfilerCallback3Impl<CBasicClrProfiler> { public: // ..[생략]... <span style='color: blue; font-weight: bold'>STDMETHOD(JITCompilationStarted)(FunctionID functionId, BOOL fIsSafeToBlock);</span> // ..[생략]... }; OBJECT_ENTRY_AUTO(__uuidof(BasicClrProfiler), CBasicClrProfiler) </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > HRESULT CBasicClrProfiler::Initialize(IUnknown * pICorProfilerInfoUnk) { // ...[생략]... DWORD dwEventMask = COR_PRF_MONITOR_MODULE_LOADS | <span style='color: blue; font-weight: bold'>COR_PRF_MONITOR_JIT_COMPILATION</span>; m_pICorProfilerInfo2->SetEventMask(dwEventMask); return S_OK; } HRESULT CBasicClrProfiler::<a target='tab' href='http://www.sysnet.pe.kr/2/0/1046'>JITCompilationStarted</a>(FunctionID functionId, BOOL fIsSafeToBlock) { ClassID classId; ModuleID moduleId = 0; mdToken methodToken = 0; HRESULT hr = m_pICorProfilerInfo2->GetFunctionInfo(functionId, &classId, &moduleId, &methodToken); if (hr != S_OK) { return S_OK; } // ========= 1. 필요한 인터페이스를 구하고, IMetaDataImport* pMetaDataImport = nullptr; IMetaDataAssemblyImport* pMetaDataAssemblyImport = nullptr; do { hr = m_pICorProfilerInfo2->GetModuleMetaData(moduleId, (ofRead | ofWrite), IID_IMetaDataAssemblyImport, (LPUNKNOWN *)&pMetaDataAssemblyImport); if (hr != S_OK) { break; } hr = pMetaDataAssemblyImport->QueryInterface(IID_IMetaDataImport, (LPVOID *)&pMetaDataImport); if (hr != S_OK) { break; } ULONG cchFunction; mdToken typeToken; wchar_t szFunction[2048] = { 0 }; wchar_t szClass[2048] = { 0 }; // ========= 2. 메서드 이름을 구하고, hr = pMetaDataImport->GetMethodProps(methodToken, &typeToken, szFunction, 2048, &cchFunction, NULL, NULL, NULL, NULL, NULL); if (hr != S_OK) { break; } if (wcscmp(szFunction, L"DoMethod") != 0 && wcscmp(szFunction, L"Main") != 0) { break; } // ========= 3. 타입명을 구하고, ULONG cchClass; hr = pMetaDataImport->GetTypeDefProps(typeToken, szClass, 2048, &cchClass, 0, 0); if (hr != S_OK) { break; } <span style='color: blue; font-weight: bold'>wprintf(L"[Jitted] %s.%s", szClass, szFunction);</span> } while (false); if (pMetaDataImport != nullptr) { pMetaDataImport->Release(); pMetaDataImport = nullptr; } if (pMetaDataAssemblyImport == nullptr) { pMetaDataAssemblyImport->Release(); pMetaDataAssemblyImport = nullptr; } return S_OK; } </pre> <br /> 이제 실행하면, 각 모드에 따라 다음과 같은 결과를 볼 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ================ LoaderOptimization.SingleDomain ... <span style='color: blue; font-weight: bold'>[Jitted] ConsoleApplication1.Program.Main</span> ... <span style='color: blue; font-weight: bold'>[Jitted] StrongDLL.Class1.DoMethod</span> StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7110820 <span style='color: blue; font-weight: bold'>[Jitted] WeakDLL.Class1.DoMethod</span> WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7110b90 ... <span style='color: blue; font-weight: bold'>[Jitted] StrongDLL.Class1.DoMethod</span> StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7180630 <span style='color: blue; font-weight: bold'>[Jitted] WeakDLL.Class1.DoMethod</span> WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab71809a0 </pre> <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ================ LoaderOptimization.MultiDomainHost ... <span style='color: blue; font-weight: bold'>[Jitted] ConsoleApplication1.Program.Main</span> ... <span style='color: blue; font-weight: bold'>[Jitted] StrongDLL.Class1.DoMethod</span> StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7140c30 <span style='color: blue; font-weight: bold'>[Jitted] WeakDLL.Class1.DoMethod</span> WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7140f90 ... StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7140c30 <span style='color: blue; font-weight: bold'>[Jitted] WeakDLL.Class1.DoMethod</span> WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab71b0680 </pre> <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // ================ LoaderOptimization.MultiDomain ... <span style='color: blue; font-weight: bold'>[Jitted] ConsoleApplication1.Program.Main</span> ... <span style='color: blue; font-weight: bold'>[Jitted] StrongDLL.Class1.DoMethodStrongDLL.Class1.DoMethod called (times: 0)</span> JIT Address: 0x7ffab7150780 <span style='color: blue; font-weight: bold'>[Jitted] WeakDLL.Class1.DoMethodWeakDLL.Class1.DoMethod called (times: 0)</span> JIT Address: 0x7ffab7150a90 StrongDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7150780 WeakDLL.Class1.DoMethod called (times: 0) JIT Address: 0x7ffab7150a90 </pre> <br /> 역시 이번에도 결과는 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/10949'>SharedDomain과 JIT 컴파일</a>"에서 설명했던 것과 다르지 않습니다. 그리고, 당연한 이야기겠지만 AppDomain 생성을 반복하는 경우 동일한 메서드는 지속적으로 JIT 컴파일될 수 있습니다.<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1017&boardid=331301885'>첨부한 파일은 이 글의 소스 코드를 포함</a>합니다.)<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
6881
(왼쪽의 숫자를 입력해야 합니다.)