성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] VT sequences to "CONOUT$" vs. STD_O...
[정성태] NetCoreDbg is a managed code debugg...
[정성태] Evaluating tail call elimination in...
[정성태] What’s new in System.Text.Json in ....
[정성태] What's new in .NET 9: Cryptography ...
[정성태] 아... 제시해 주신 "https://akrzemi1.wordp...
[정성태] 다시 질문을 정리할 필요가 있을 것 같습니다. 제가 본문에...
[이승준] 완전히 잘못 짚었습니다. 댓글 지우고 싶네요. 검색을 해보...
[정성태] 우선 답글 감사합니다. ^^ 그런데, 사실 저 예제는 (g...
[이승준] 수정이 안되어서... byteArray는 BYTE* 타입입니다...
글쓰기
제목
이름
암호
전자우편
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'>Assembly.LoadFrom으로 로드된 어셈블리의 JIT 컴파일 코드 공유?</h1> <p> 다음의 문서에 보면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Application Domains ; <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/framework/app-domains/application-domains'>https://learn.microsoft.com/en-us/dotnet/framework/app-domains/application-domains</a> </pre> <br /> 다음과 같은 설명이 있습니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> <span style='color: blue; font-weight: bold'>JIT-compiled code cannot be shared for assemblies loaded into the load-from context</span>, using the LoadFrom method of the Assembly class, or loaded from images using overloads of the Load method that specify byte arrays. </div><br /> <br /> 즉, "Assembly.LoadFrom"으로 로드된 어셈블리는 JIT 컴파일 코드가 공유되지 않는다는 것입니다. 과연 그럴까요?<br /> <br /> 이를 테스트하려면 "<a target='tab' href='http://www.sysnet.pe.kr/2/0/10949'>SharedDomain과 JIT 컴파일</a>"의 예제 코드를 조금 변형해 보면 됩니다. 그냥 ConsoleApplication1 프로젝트의 Main 메서드에 다음과 같이 LoadFrom 사용 코드를 추가해 주는 정도면 될 듯한데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > using System; using System.IO; using System.Reflection; namespace ConsoleApplication1 { partial class Program { [LoaderOptimization(LoaderOptimization.MultiDomainHost)] static void Main(string[] args) { string path = @"..\..\..\StrongDLL\bin\Debug\StrongDLL.dll"; path = Path.GetFullPath(path); Console.WriteLine(path); // LoadFrom을 했지만, GAC로부터 로딩이 되었으면 LoadContext에 로딩 Assembly asm = Assembly.LoadFrom(path); object objClass = asm.CreateInstance("StrongDLL.Class1"); objClass.GetType().InvokeMember("DoMethod", BindingFlags.Default | BindingFlags.InvokeMethod, null, objClass, null); Console.WriteLine(objClass.GetType().Name + ", " + asm.Location); // GAC 어셈블리를 로딩하므로 역시나 LoadContext에 로딩 StrongDLL.Class1 cl = new StrongDLL.Class1(); cl.DoMethod(); string path2 = cl.GetType().Assembly.Location; Console.WriteLine(path2); Console.WriteLine(); Console.WriteLine("Press any key to exit..."); Console.ReadLine(); } } } </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;' > <span style='color: blue; font-weight: bold'>C:\shared_domain\assembly_from\StrongDLL\bin\Debug\StrongDLL.dll</span> StrongDLL.Class1.DoMethod called JIT Address: <span style='color: blue; font-weight: bold'>0x7ffab7130c30</span> <span style='color: blue; font-weight: bold'>Class1, C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll</span> StrongDLL.Class1.DoMethod called JIT Address: <span style='color: blue; font-weight: bold'>0x7ffab7130c30</span> C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll </pre> <br /> 우선, JIT Address의 값이 0x7ffab7130c30으로 동일합니다. 즉, JIT 주소가 공유되었다는 것입니다. 그런데, 이럴 수밖에 없는 것이 애당초 LoadFrom으로 로드했어도 로컬 폴더의 StrongDLL.dll을 로드한 것이 아니고 GAC에 있는 것이 로드되었기 때문입니다.<br /> <br /> 즉, 원래부터 GAC에 등록된 어셈블리라면 LoadFrom으로 로드한다고 해도 결국 GAC에 있는 DLL을 로드하기 때문에 SharedDomain에 등록되어 공유되는 것입니다. 그럼, 이에 기반해서 해당 문서를 다시 한번 볼까요?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > JIT-compiled code cannot be shared for assemblies loaded into the load-from context, using the LoadFrom method of the Assembly class, or loaded from images using overloads of the Load method that specify byte arrays. </pre> <br /> 그러니까, 위의 설명을 적용할 수 있는 경우라면 GAC에 등록되지 않은 어셈블리를 로드하는 것일 텐데, 어차피 그 상황에서는 MultiDomainHost 모드에서 개별 AppDomain에 로드되어 공유되지 않으므로 저 문서의 내용이 굳이 명시될 필요가 없는 것입니다. (혹시, 이 문서의 내용에 부합하는 예제를 아시는 분은 덧글 좀 부탁드립니다. ^^)<br /> <br /> 말 나온 김에, 비-도메인 중립적인 어셈블리인 경우도 마저 테스트 해보겠습니다. 가령, 강력한 이름을 갖지 않은 WeakDLL에 대해 다음과 같이 LoadFrom을 함께 사용해 주면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > string path = @".\WeakDLL.dll"; path = Path.GetFullPath(path); Console.WriteLine(path); // LoadFrom을 해도 AppDomain.CurrentDomain.BaseDirectory 및 CLR이 어셈블리를 검색하는 경로에 포함된 경우라면 LoadContext에 로딩 Assembly asm = Assembly.LoadFrom(path); object objClass = asm.CreateInstance("WeakDLL.Class1"); objClass.GetType().InvokeMember("DoMethod", BindingFlags.Default | BindingFlags.InvokeMethod, null, objClass, null); Console.WriteLine(objClass.GetType().Name + ", " + asm.Location); WeakDLL.Class1 cl = new WeakDLL.Class1(); // 당연히 LoadContext에 로딩 cl.DoMethod(); string path2 = cl.GetType().Assembly.Location; Console.WriteLine(path2); Console.WriteLine(); Console.WriteLine("Press any key to exit..."); Console.ReadLine(); </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C:\shared_domain\assembly_from\ConsoleApplication1\bin\Debug\WeakDLL.dll WeakDLL.Class1.DoMethod called JIT Address: <span style='color: blue; font-weight: bold'>0x7ffab7130fc0</span> Class1, C:\shared_domain\assembly_from\ConsoleApplication1\bin\Debug\WeakDLL.dll WeakDLL.Class1.DoMethod called JIT Address: <span style='color: blue; font-weight: bold'>0x7ffab7130fc0</span> C:\shared_domain\assembly_from\ConsoleApplication1\bin\Debug\WeakDLL.dll </pre> <br /> 역시 JIT 컴파일 주소에는 변함이 없습니다. 재미있는 점은, 같은 DLL파일이라도 경로를 다르게 해서 (어느 한 개를 반드시 LoadFromContext에 로딩이 되도록) LoadFrom을 하면 JIT 컴파일 주소가 바뀝니다. 아마도 Load/LoadFrom의 문맥에 따라 바뀐 때문인 듯한데, 이 때문에 같은 AppDomain에 로드된 2개의 어셈블리가 '같은 DLL'이라고 해도 Load/LoadFrom에 따라 JIT 컴파일이 발생할 수 있음을 알아야 합니다.<br /> <br /> 테스트하고 보니, 어쩌면 해당 문서의 내용이 Load/LoadFrom 문맥을 의미하는 것일지도 모르겠습니다. 단지, 좀 더 정확한 표현으로 "GAC에 등록되지 않은 어셈블리이면서 경로가 다른 경우"로 한정지으면 더 좋을 듯합니다.<br /> <br /> (<a target='tab' href='http://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1019&boardid=331301885'>첨부 파일은 이 글의 예제 코드</a>입니다.)<br /> </p><br /> <br /> <br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
1987
(왼쪽의 숫자를 입력해야 합니다.)