본문 바로가기

IT 살이/04. 기술 - 프로그래밍

BindingContext - Load() vs. LoadFrom()

달봉이가 가끔 부딪치고 있는 두 개념 LoadContextLoadFromContext에 대해서 정리해 볼까 한다.

Loaded Assembly Cache

바인딩 컨텍스트(binding context)라는 것이 있는데, Junfeng Zhang(이 사람 이름은 어떻게 발음해야 할지 달봉이는 항상 고민이다)에 의하면 로딩된 어셈블리의 캐시(loaded assembly cache)로 말하고 있다. 우리가 익히 알고 있는 GAC(Global assembly cache)도 바인딩과 프로빙 과정을 거치지 않도록 할 수 있다는 점에 어떻게 보면 캐시라고 볼 수도 있을 것이다. 그리고 NTD에 의해 배포된 어셈블리가 캐싱되는 어셈블리 다운로드 캐시(assembly download cache)도 있다. 허나 이런 캐시들은 파일 시스템 상의 캐시로서 로딩되지 않은 어셈블리를 위한 것이다. 이미 로딩되어 있는 어셈블리는 다시 로딩하지 않고 바인딩 컨텍스트에 있는 것을 사용하게 되는 것이다. LoadFrom(경로)처럼 직접 어셈블리의 경로를 통해서 로딩하는 경우도 loaded assembly cache를 먼저 확인하고 나서 없다면 경로의 어셈블리를 로딩한다.

When to load assembly


애플리케이션 실행되고 나서 새로운 타입(클래스 포함)이 나타나면 그 타입이 포함된 어셈블리를 로딩하게 되는데, 호출하는 어셈블리는 참조되는 대상 어셈블리 및 그 타입에 대한 모든 정보를 어셈블리의 일부인 메너페스트라는 곳에 가지고 있다. 이 정보를 통해서 대상 어셈블리를 결정하고 로딩하게 되는 것이다. 자세한 것은 어셈블리 구조를 설명하는 포스트를 참조하기 바란다.
많은 경우가 이렇게 정적인 참조에 의해 어셈블리를 로딩하지만 또한 어셈블리를 Load() LoadFrom()등을 사용해서 동적으로 로딩하는 경우도 많다.

LoadContext vs. LoadFromContext


다시 바인딩 컨텍스트(binding context) 얘기로 돌아가보면... "바인딩 컨텍스트"란 로딩된 어셈블리의 캐시라고 했는데, "바인딩 컨텍스트"라는 용어 자체에는 "캐시"를 암시하는 것은 없다. 대신에 도메인처럼 어떤 영역을 구분짓는데 사용하는 컨텍스트(context)라는 단어가 사용되고 있다. 그렇다. 우리의 추측에 부합하는 용어의 선택이다. 바인딩 컨텍스트라는 것은 단순히 로딩된 어셈블리의 캐시라는 원래의 의미에 추가하여 어셈블리 바인딩(assembly binding)과 관련된 의미를 가지고 있다. 즉 다른 바인딩 방법에 의해 로딩된 어셈블리는 다른 캐시에 저장되고, 이것을 구분하여 두 바인딩을 대표하는 메소드 Load LoadFrom의 이름을 따서 LoadContext LoadFromContext로 구분해서 사용하고 있다.

GAC, AppDomain의 ApplicationBase 또는 PrivateBinPath상에 있는 디렉토리 등에 있는 어셈블리는 LoadContext로 로딩된다.

어셈블리를 로딩하는데, 파일에 대한 경로를 이용하는 경우, 해당 어셈블리가 LoadContext에서 발견되지 못하면 결국 해당 경로에 있는 어셈블리를 가지고 와서 LoadFromContext에 캐싱한다. 이렇게 경로를 이용해서 어셈블리를 로딩하는 방법은 LoadFrom() 메소드외에도 CreateInstanceFrom(), ExecuteAssembly() 등이 있다. 그리고 codebase 값을 사용하여 어셈블리를 로딩하는 경우도 LoadFromContext로 로딩된다.

참고로 위치 기반의 어셈블리 로딩시는 바인딩이 두번 일어난다는 것을 상기하자. 즉 LoadFrom()을 호출하면, 경로에 있는 어셈블리 파일로 부터 이름 정보를 얻어서 다시 내부적으로 Load()가 호출된다.
참조에 의해 로딩된 어셈블리와 Load() 메소드 및 그 자식 어셈블리들(Load() 메소드에 의해서 로딩된 어셈블리에서 참조하는 다른 어셈블리들)로 로딩된 어셈블리는 같은 LoadContext에 저장된다. 그리고 LoadFrom()또는 CreateInstanceFrom()처럼 경로를 기반으로 해서 로딩된 어셈블리와 그 자식 어셈블리들은 LoadFromContext에 저장된다.

공유 불가


두 캐시의 컨텍스트가 다르다함은 그 용어에서 느껴지는 것처럼 서로 공유되지 않는 다른 특징이 있다. 동일한 어셈블리가 다른 바인딩 컨텍스트에 캐싱되어 있을 수도 있다는 것이다.

LoadContext의 어셈블리가 참조하는 다른 어셈블리가 LoadFromContext에 캐싱되어 있다면 그 어셈블리는 사용할 수 없다. 그 어셈블리를 다시 LoadContext로 로딩시키게 된다.

그러나 LoadFromContext에서는 LoadContext에 있는 어셈블리를 사용할 수 있게 있다. 이것은 LoadFrom() 메소드의 두번째 바인딩때 LoadContext를 검색하기 때문이다. LoadFrom()의 두번의 바인딩에 대해서는 지난 포스트를 참조한다.

버전 정책 사용 여부


LoadContext
에서는 버전 정책을 사용해서 소위 “DLL Hell”을 피할 수 있다. 그러나 LoadFromContext로 로딩된 어셈블리에 대해서는 버전 정책을 사용할 수 없다.



참조 문서

기타 자세한 내용은 다음 블로그를 참조할 수 있다. Binding ContextLoadContext, LoadFromContext에 대한 설명이 자세히 나와있다.

Binding Context and LoadFrom by Junfeng Zhang
LoadFile vs. LoadFrom by Suzanne Cook
Choosing a Binding Context by Suzanne Cook

Reflection Only Assembly Loading

다음 블로그를 보면 V2.0 이전에서는 LoadFrom()에서도 바인딩이 두번 일어난다는 것을 알수 있다.
LoadFrom's Second Bind-Suzanne Cook's blog
http://blogs.msdn.com/suzcook/archive/2003/09/16/57247.aspx