Roslyn에서 Emit한 어셈블리 unload 하기

이것도 어떤 분께서 하신 질문에 대한 좀 더 자세한 답변을 블로그로 올리는 것입니다. 앞에 블로그에도 썼듯이, 이 답변은 현재 Roslyn CTP에 공개된 내용만을 바탕으로 하는것이니 만큼 final version에서는 얼마든지 바뀔수 있습니다.

 

일단 질문은 Roslyn으로 compile 에서 만들어진 어셈블리들은 일단 메모리에 load된 후에 unload가 가능한가 입니다. 일단 답변은 unload가 가능한것도 있고 불가능한것도 있다 입니다.

 

일단 Roslyn에는 2가지 방식의 Emit이 있습니다. 첫번째는 CCI를 이용한 Emit이고, 두번째는 Reflection을 이용한 Emit입니다. 그중 CCI를 이용하는 Emit의 경우, 그 결과를 stream에 넣어줍니다. 이걸 메모리로 로드할 경우, 일반적인 어셈블리를 메모리로 로드한 경우와 같이, 후에 이 어셈블리만 unload 하실순 없습니다. 여태 해왔듯이 다른 app domain으로 로드 하신 후, 그 app domain을 내리셔야 합니다. Reflection을 이용하는 Emit의 경우, 자동으로 결과물을 메모리에 올리게 됩니다. 이때 가능하면 Collectible한 다이나믹 어셈블리를 메모리에 올리게 됩니다. 콜렉터블한 어셈블리가 만들어졌는지 아닌지는, Emit이 돌려주는 ReflectionEmitResult.IsUncollectible로 확인하실수 있습니다. dynamic assembly와 collectible assembly에 대한 보다 자세한 내용은 여기에 나와 있습니다.

 

간단하게 말해, Stream에 emit 하는 경우, 일반적인 다른 경우와 똑같고, 여태 해오시던데로 하시면 되고, Reflection을 통해 emit 할 경우, Roslyn에서 기존 .NET에서 제공하던 가장 밑단의 API 위에, 좀 더 사용하기 쉬운 Emit API를 올렸고, 가능한 한 후에 콜렉터블한 다이나믹 어셈블리를 emit 하지만, 만약 코드에서 콜렉터블이 블가능한 구문들을 사용했을 경우, 콜렉터블 하지 않은 어셈블리를 emit 한 후에, caller에게 그 사실을 알려준다는 것입니다. 어떤 경우 콜렉터블 하지 않는지는 위의 링크에 설명 되어 있습니다.

 

아무 신경 쓰고 싶지 않으시다면, 그냥 전처럼 다른 app domain에 올리신 후에, 맨 끝에 그 app domain 내리시면 됩니다. 어떤 분께서 언제 언로드가 제공될지 물으셨는데, 저도 앞으로 어찌될지는 모르겠습니다 Smile

 

참고로, 밑에는 Rolsyn.Compilers.CSharp.Compilation 에 있는 3개의 Emit 시그니쳐 입니다.

 

public ReflectionEmitResult Emit(ModuleBuilder moduleBuilder, Roslyn.Compilers.IAssemblyLoader assemblyLoader = null, Func<AssemblySymbol, AssemblyName> assemblySymbolMapper = null, CancellationToken cancellationToken = null);

public EmitResult Emit(Stream executableStream, string pdbFileName = null, Stream pdbStream = null, Stream xmlDocStream = null, CancellationToken cancellationToken = null, Func<string, Stream> xmlNameResolver = null, Stream win32ResourcesInRESFormat = null, IEnumerable<Roslyn.Compilers.ResourceDescription> manifestResources = null);

public EmitResult EmitMetadataOnly(Stream metadataStream, Stream xmlDocStream = null, CancellationToken cancellationToken = null, Func<string, Stream> xmlNameResolver = null);

 

감사합니다. 질문 주시면 또 블로그로 답변 드리도록 하겠습니다.

수고.

- 희제