본문 바로가기

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

GAC은 어떻게 생겼을까

GAC(Global Assembly Cache)

GAC(Global Assembly Cache)은 머신 차원의 공용 저장소로 이곳에 등록된 어셈블리는 머신에 설치된 모든 애플리케이션에서 같이 사용할 수 있다. 여러 애플리케이션에서 어셈블리에 접근하려면 그 어셈블리는 CLR이 인식할 수 있는 디렉토리에 있어야 한다. 참조하는 어셈블리를 애플리케이션이 로딩하려고 하면 CLR은 자동적으로 미리 정해진 그 디렉토리 구조를 따라가며 검색할 것이다.

GAC은 CLR이 이해할 수 있는 디렉토리 구조를 갖는다. GAC은 그러나 단순한 디렉토리가 아니다. 어셈블리의 버전닝 정책 즉 파일명은 같지만 버전번호가 다른 어셈블리가 동시에 존재할 수 있는 디렉토리 구조이며, 그리고 우연히 두 회사에서 출시한 어셈블리의 파일명이 같더라도 회사의 기밀 사항인 공개키/전용키 값이 다른 어셈블리가 동시에 존재할 수 있는 구조이다. 또한 어셈블리의 충돌을 피하기 위한 수단으로 GAC에 등록하려는 어셈블리는 반드시 디지털 사인과 공개키를 갖고 있어야 한다.

GAC의 내부 저장 구조는 어셈블리의 버전 정책을 이해하는데 도움이 된다.  GAC에 등록된 어셈블리의 내용을 보려면 다음을 수행한다.

시작->실행 창에서 "assembly"

이렇게 하면 윈도우 탐색기가 뜨지만 일반 디렉토리 구조와는 다른 내용이 출력된다.
1301365642

assembly 디렉토리 내용

GAC에 어셈블리를 등록시키기 위해서는 해당 어셈블리는 반드시 strongly named assembly이어야 한다. VS.NET으로 개발한다면 assemblyinfo.cs 파일에는 반드시 다음처럼 키파일(key file)을 지정하는 코드가 있어야 한다[각주:1]

[assembly: AssemblyKeyFile("..\\..\\mykey.snk")]

이렇게 생성된 어셈블리는 gacutil.exe 커맨드 툴을 사용해서 GAC에 등록할 수 있다. GAC에 등록하고 GAC에서 삭제하는 명령어는 다음과 같다.

gacutil.exe /i myassembly.dll
gacutil.exe /u myassembly
gacutil.exe /u myassembly, Version=1.1.0.0, Culture=ko-KR, PublicKeyToken=123456789012

옵션 “/i 어셈블리파일명”을 사용하면 어셈블리를 GAC에 등록할 수 있다. GAC에서 삭제할때는 /u 옵션을 사용하는데, “/u 어셈블리명” 명령어를 사용하면 버전, 컬쳐, 공개키토큰이 다를지라도 동일한 어셈블리명 파일명을 갖는 모든 어셈블리를 GAC에서 삭제한다. 동일한 파일명의 어셈블리가 동시에 있을 경우, 특정 어셈블리만 삭제하고 싶은 경우는 완전한 어셈블리명을 인자로 주면 된다.

윈도우 탐색기를 이용해서 assembly 폴더를 보면 하나의 폴더안에 모든 어셈블리가 저장되어 있는 것처럼 보이지만 실제로는 그렇지 않다. 단순한 단일 계층의 구조로 보이지만 GAC내부는 실제로 동일한 파일명을 가지고 있더라도 어셈블리명의 4가지 구성요소에 따라 다른 곳에 저장될 수 있는 디렉토리 계층 구조를 갖는다. 다음은 달봉이의 로컬 머신에서 명령 프롬프트 창을 실행해서 C:\Windows\Assembly\GAC 디렉토리 내용을 본 모습이다.
1070794810

GAC내부#1

C:\Windows\Assembly\GAC에는 GAC에 등록된 어셈블리별로 하나씩 하위 디렉토리가 있다. 이 디렉토리중에서 하나의 하위로 들어가면 또 하나 이상의 하위 디렉토리가 있다.
1311574477

GAC내부#2

System 디렉토리의 하위에는 다시 “1.0.5000.0__b77a5c561934e089” 디렉토리가 있다. 이 디렉토리명은  “버전_컬쳐_공개키토큰”으로 구성된다. 달봉의 머신에는 System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken= b77a5c561934e089”의 어셈블리가 인스톨되어 있다. 다시 이 디렉토리를 들어가보면 이 어셈블리파일이 있다. 만약 다른 버전의 System.dll 등록되어 있다면 다른 그 어셈블리는 다른 디렉토리에 저장되어 있을 것이고 그 디렉토리 경로는 다음과 같은 형식을 취할 것이다.

\GAC\System\버전번호__b77a5c561934e089

GAC의 내부 구조가 이러하므로 GAC에는 동일한 파일명을 갖는 어셈블리가 여러 버전으로 등록될 수 있다. 또한 이러한 구조 때문에 GAC에 등록된 어셈블리와 바인딩을 할때는 CLR은 어셈블리의 완전한 이름을 검색한다. 어셈블리 바인딩과 로딩에 대해서는 뒤의 Assembly Resolver, Assembly Loader에서 다룬다. 

GAC에 어셈블리를 등록할때는 단순히 어셈블리에 해당하는 디렉토리를 구성하고 그곳에 어셈블리 복사본을 저장하는 일만 일어나는 것은 아니다.  GAC에 등록될 때, CLR은 공개키, 디지털 사인을 이용하여 해킹에 의한 코드가 변경되었는지도 체크하게 된다. 사인 연기(delayed signing)을 이용해서 코드 변경 체크를 건너뛸 수도 있다.

  1. VS.NET 2005버전에서는 키파일을 지정하는 방법이 직접 assembly.cs 파일을 수정하는 대신에 키파일을 선택하는 속성 폼이 따로 있다. 하지만 역시 내부적으로 assembly.cs를 우리 대신에 수정해 준다. [본문으로]