성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] Java - How to use the Foreign Funct...
[정성태] 제가 큰 실수를 했군요. ^^; Delegate를 통한 Bein...
[정성태] Working with Rust Libraries from C#...
[정성태] Detecting blocking calls using asyn...
[정성태] 아쉽게도, 커뮤니티는 아니고 개인 블로그입니다. ^^
[정성태] 질문이 잘 이해가 안 됩니다. 우선, 해당 소스코드에서 ILis...
[양승조
] var대신 dinamic으로 선언해서 해결은 했습니다. 맞는 해...
[양승조
] 또 막혔습니다. ㅠㅠ var list = props[i].Ge...
[양승조
] 아. 감사합니다. 어제는 안됐던것 같은데....정신을 차려야겠네...
[정성태] "props[i].GetValue(props[i])" 코드에서 ...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <br /> <div class='mainCenterTitle'>XmlSerializer 생성자의 실행 속도를 올리는 방법</div><br /> <br /> 지금쯤이면 이미 많은 분들이 아시는 내용이겠지만. 그래도 한번 정리를 해보고 지나가야 할 내용 같아서 써봅니다.<br /> <br /> XmlSerializer 생성자에 타입을 전달하는 코드가 처음 실행될 때, 생성자안에서는 타입에 해당하는 직렬화 코드가 이미 있는지를 먼저 찾아보게 됩니다. 만약 없다면, 새롭게 해당 클래스를 직렬화하는 코드를 동적으로 생성해서 로드하게 됩니다.<br /> <br /> 왜냐하면, 직렬화를 위해서는 반드시 해당 클래스를 일일이 "Reflection"을 통해서 조사해야 하는데, 여기에서 오는 속도 저하가 심각하기 때문에, 아예 처음 한번은 Reflection을 이용해서 직렬화를 해주는 동적 코드를 생성하는 것으로 이 문제를 해결하고 있습니다.<br /> <br /> 어디... 눈으로 한번 확인해 볼까요?<br /> <br /> 우선, VS.NET의 "도구" / "옵션" 창에서 "<a target='_tab' href='/2/0/317#enable_just_my_code'>Enable Just My Code</a>" 옵션을 해제하십시오.<br /> <br /> 그런 다음, 아래와 같은 코드를 작성해서 빌드한 후, 굵은 글씨로 되어 있는 부분에 BP(Break Point)를 설정한 후 "F5" 디버깅 모드로 실행시켜 보십시오.<br /> <br /> <pre class='code'> public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { MyClass myClass = new MyClass(); <b>XmlSerializer xs = new XmlSerializer(typeof(MyClass));</b> // BP(Break Point) 설정 } } public class MyClass { public string Prop; } </pre> <br /> "F10" 키를 눌러서 라인을 실행시키면, VS.NET의 "Output" 창에는 다음과 같은 내용이 출력되는 것을 확인할 수 있습니다.<br /> <br /> <pre class='code'> A first chance exception of type '<b>System.IO.FileNotFoundException</b>' occurred in mscorlib.dll A first chance exception of type 'System.IO.FileNotFoundException' occurred in mscorlib.dll 'XmlSerializerTest.vshost.exe' (Managed): Loaded '<b>7ptbpl3m</b>', No symbols loaded. </pre> <br /> 지난 회를 통해서, 우리는 <a target='_tab' href='/2/0/510'>"first chance exception"</a>이 무엇인지 이미 설명을 드렸으니... 이젠 낯설지 않으시죠? ^^<br /> <br /> 그런데,,, 그냥 호기심 삼아서 위의 예외가 언제 발생하는지 추적해 볼까요?<br /> 소스 코드가 없다면 좀 단계가 어렵지만, 마이크로소프트에서 공개하고 있는 "Shared Source CLR"의 XmlSerializer 소스를 살펴보면 그 호기심을 쉽게 풀수가 있습니다. <br /> <br /> <pre class='code'> Shared Source Common Language Infrastructure Archive ; <a target='_tab' href='https://github.com/SSCLI'>https://github.com/SSCLI</a> </pre> <br /> 다운로드 받아서, 아래와 같이 XmlSerializer 생성자를 살펴보면 다음과 같은 소스 코드를 확인할 수 있습니다.<br /> <br /> <pre class='code'> .\fx\src\xml\system\xml\serialization\xmlserializer.cs ; <a target='tab' href='https://github.com/SSCLI/sscli20_20060311/blob/master/fx/src/xml/system/xml/serialization/xmlserializer.cs'>https://github.com/SSCLI/sscli20_20060311/blob/master/fx/src/xml/system/xml/serialization/xmlserializer.cs</a> public XmlSerializer(Type type, string defaultNamespace) { if (type == null) throw new ArgumentNullException("type"); this.mapping = GetKnownMapping(type, defaultNamespace); if (this.mapping != null) { this.primitiveType = type; return; } <b> tempAssembly = cache[defaultNamespace, type]; if (tempAssembly == null) { </b> lock (cache) { tempAssembly = cache[defaultNamespace, type]; if (tempAssembly == null) { XmlSerializerImplementation contract; <b> Assembly assembly = TempAssembly.LoadGeneratedAssembly(type, defaultNamespace, out contract); </b> if (assembly == null) { </pre> <br /> cache에 없으니, TempAssembly.LoadGeneratedAssembly를 이용해서, 관련 직렬화 클래스를 로드해 봅니다. 만약 이때 로드가 안되면(assembly == null) 이후에 동적으로 생성하는 코드가 이어지는데, 여기서는 생략하고 예외가 발생하는 LoadGeneratedAssembly 메서드를 좀 더 추적해 보도록 하겠습니다.<br /> <br /> <pre class='code'> .\fx\src\xml\system\xml\serialization\compilation.cs ; <a target='tab' href='https://github.com/SSCLI/sscli20_20060311/blob/master/fx/src/xml/system/xml/serialization/compilation.cs'>https://github.com/SSCLI/sscli20_20060311/blob/master/fx/src/xml/system/xml/serialization/compilation.cs</a> internal static Assembly LoadGeneratedAssembly(Type type, string defaultNamespace, out XmlSerializerImplementation contract) { Assembly serializer = null; contract = null; string serializerName = null; bool logEnabled = DiagnosticsSwitches.PregenEventLog.Enabled; // check to see if we loading explicit pre-generated assembly object[] attrs = type.GetCustomAttributes(typeof(XmlSerializerAssemblyAttribute), false); if (attrs.Length == 0) { // Guess serializer name: if parent assembly signed use strong name AssemblyName name = GetName(type.Assembly, true); serializerName = Compiler.GetTempAssemblyName(name, defaultNamespace); // use strong name name.Name = serializerName; name.CodeBase = null; name.CultureInfo = CultureInfo.InvariantCulture; try { serializer = <b>Assembly.Load(name);</b> } catch (<b>Exception</b> e) { if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { throw; } byte[] token = name.GetPublicKeyToken(); if (token != null && token.Length > 0) { // the parent assembly was signed, so do not try to LoadWithPartialName return null; } #pragma warning disable 618 serializer = <b>Assembly.LoadWithPartialName(serializerName, null);</b> #pragma warning restore 618 </pre> <br /> 아하, 이 코드들을 보니 답이 나왔군요. ^^ Assembly.Load에서 "first-chance exception(System.IO.FileNotFoundException)"이 한번 발생하고, 이후에 Assembly.LoadWithPartialName에서 다시 한번 내부적으로 "first-chance exception(System.IO.FileNotFoundException)"이 발생하고 있습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 이렇게 XmlSerializer의 생성자에 전달되는 Type 하나 당 2번의 예외가 발생합니다. 한 두번 정도야 상관없겠지만, 알게 모르게 참조하는 DLL들 내부에서 이런 초기 예외가 빈번하게 발생하게 되면 눈에 띄는 실행속도 저하가 발생할 수 있습니다. (물론, 일단 한번 cache가 된다면 그 이후에는 빠르게 로드가 되지만.)<br /> <br /> 그런데, 도대체 어떤 이름의 파일을 로드하려고 시도했던 것일까요? ^^ 해답을 찾을 수 있는 방법을 이미 지난번에 다뤄보았던 "<a target='_tab' href='/2/0/510'>First-Chance Exception</a>" 토픽에서 설명해 놓았으니 이 부분은 건너뛰도록 하겟습니다.<br /> <br /> 자... 그럼 이 문제를 해결하려면 어떻게 해야 할까요?<br /> <br /> 간단합니다. ^^ System.IO.FileNotFoundException이 발생하지 않도록 직렬화 관련 클래스를 미리 생성시켜 두면 됩니다. 바로 이런 목적을 위해 "<a target='_tab' href='https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-2.0/bk3w6240(v=vs.80)'>sgen.exe</a>" 파일이 제공되고 있습니다.<br /> <br /> XmlSerializer 생성자에 전달되는 Type이 포함된 Assembly 파일을 인자로 전달하면 되는데, 만약 위의 예제 코드에서 "MyClass" 타입이 포함된 Assembly 파일명이 "ClassLibrary1.dll"이라면 다음과 같이 실행해 줄 수 있습니다.<br /> <br /> <pre class='code'> C:\XmlSerializerTest\bin\Debug><b>sgen ClassLibrary1.dll</b> Microsoft (R) Xml Serialization support utility [Microsoft (R) .NET Framework, Version 2.0.50727.42] Copyright (C) Microsoft Corporation. All rights reserved. Serialization Assembly Name: ClassLibrary1.XmlSerializers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null. Generated serialization assembly for assembly C:\XmlSerializerTest\bin\Debug\classlibrary1.dll --> 'C:\XmlSerializerTest\bin\Debug\<b>ClassLibrary1.XmlSerializers.dll</b>'. C:\XmlSerializerTest\bin\Debug> </pre> <br /> 자, 이제 다시 한번 "F5" 키를 눌러서 디버깅 모드로 진입하면 이번에는 "first-chance exception"이 전혀 발생하지 않습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 끝으로 읽을 거리 하나 제시하고 마치겠습니다. ^^ <br /> <br /> <pre class='code'> Avoid UAC prompt in IE component ; http://blogs.msdn.com/carloc/archive/2007/06/22/avoid-uac-prompt-in-ie-component.aspx ; <a target='tab' href='https://www.cloudnotes.io/avoid-uac-prompt-in-ie-component/'>https://www.cloudnotes.io/avoid-uac-prompt-in-ie-component/</a> </pre> <br /> 비스타 환경에서의 스마트 클라이언트 구동에 있어서 XmlSerializer와 관련한 재미있는 문제들이 지적되고 있습니다.<br /> <br /><br /><hr /><span style='color: Maroon'>[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
4600
(왼쪽의 숫자를 입력해야 합니다.)