Microsoft MVP성태의 닷넷 이야기
.NET Framework: 574. .NET - 눈으로 확인하는 SharedDomain의 동작 방식 [링크 복사], [링크+제목 복사]
조회: 15694
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 5개 있습니다.)
(시리즈 글이 6개 있습니다.)
.NET Framework: 574. .NET - 눈으로 확인하는 SharedDomain의 동작 방식
; https://www.sysnet.pe.kr/2/0/10948

.NET Framework: 575. SharedDomain과 JIT 컴파일
; https://www.sysnet.pe.kr/2/0/10949

.NET Framework: 577. CLR Profiler로 살펴보는 SharedDomain의 모듈 로드 동작
; https://www.sysnet.pe.kr/2/0/10951

.NET Framework: 578. 도메인 중립적인 어셈블리가 비-도메인 중립적인 어셈블리를 참조하는 경우
; https://www.sysnet.pe.kr/2/0/10952

닷넷: 2220. C# - .NET Framework 프로세스의 LoaderOptimization 설정을 확인하는 방법
; https://www.sysnet.pe.kr/2/0/13568

닷넷: 2221. C# - LoadContext, LoadFromContext 그리고 GAC
; https://www.sysnet.pe.kr/2/0/13569




.NET - 눈으로 확인하는 SharedDomain의 동작 방식

간단히 말하면, "SharedDomain"은 도메인-중립적인 어셈블리들의 보관소입니다. 이름에 "Domain"이 붙기 때문에 혼동이 좀 오는데 정확히 말하면 SharedDomain은 AppDomain이 아닌 것입니다. 단지 그 수준이 AppDomain에서 다뤄지기 때문에 "SharedDomain"이라고 불리는 것이 자연스럽기는 합니다.

이 때문에, 닷넷 응용 프로그램에서 "SharedDomain"을 나열할 수 있는 방법이 없습니다. 단순히 AppDomain이라면 다음의 글에 나온대로,

Hot to get list of all AppDomains inside current process? 
; http://miteshsureja.blogspot.kr/2012/02/hot-to-get-list-of-all-appdomains.html

코드를 작성하면 확인할 수 있습니다.

using System;
using System.Collections.Generic;
using mscoree;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CreateDomain("TestAppDomain 1");

            DisplayAppDomains();

            /* 
            
            출력 결과:
            
            ConsoleApplication1.exe
            TestAppDomain 1
            
            */
        }

        private static void DisplayAppDomains()
        {
            List<AppDomain> appDomains = new List<AppDomain>();
            IntPtr handle = IntPtr.Zero;

            // CLR2 x86: C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscoree.tlb
            // CLR2 x64: C:\Windows\Microsoft.NET\Framework64\v2.0.50727\mscoree.tlb

            // CLR4 x86: C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoree.tlb
            // CLR4 x64: C:\Windows\Microsoft.NET\Framework64\v4.0.30319\mscoree.tlb

            // 또는, mscoree.tlb 참조 없이 ICorRuntimeHost를 정의해 직접 사용
            CorRuntimeHost host = new CorRuntimeHost();

            try
            {
                host.EnumDomains(out handle);

                while (true)
                {
                    object domain;
                    host.NextDomain(handle, out domain);
                    if (domain == null)
                        break;
                    appDomains.Add((AppDomain)domain);
                }
            }
            finally
            {
                host.CloseEnum(handle);
            }

            foreach (AppDomain appDom in appDomains)
            {
                Console.WriteLine(appDom.FriendlyName);
            }
        }
    }
}

실행해 보면 SharedDomain에 관한 어떤 정보도 얻을 수 없습니다.




그런데, 도대체 SharedDomain이 왜 나온 것일까요?

이를 이해하려면 AppDomain을 먼저 알아야 합니다. AppDomain은, EXE 내부에서의 '닷넷의 또 다른 보안 격리 공간'입니다. 동작 방식은 간단합니다. AppDomain 공간이 있고, 그 단위로 보안 설정을 할 수 있습니다. 따라서, 신뢰하지 않는 웹 사이트로부터 DLL을 다운로드 받았다면 낮은 권한을 갖는 AppDomain을 생성해 그 안에서 해당 DLL을 로드해 실행해 볼 수 있습니다. 덕분에, 신뢰할 수 없는 DLL의 코드를 안전하게 실행해 볼 수 있는 것입니다.

AppDomain이 사용되는 대표적인 응용 프로그램이 바로 ASP.NET입니다. ASP.NET은 서로 다른 '웹 응용 프로그램'을 하나의 w3wp.exe에서 실행할 수 있게 해주는데, 이때 각각의 '웹 응용 프로그램'은 별도의 AppDomain 별로 할당되어 보안상 격리되기 때문에 하나의 EXE를 공유하지만 서로 침범할 수 없어 'security'를 보장 받을 수 있습니다.

데스크톱 응용 프로그램에서도 유용한 경우가 있습니다. 가령, 윈도우 폼 응용 프로그램의 경우 3rd-party 컨트롤을 로드할 수 있도록 /extension 이라는 폴더를 제공한다고 가정했을 때 그 폴더에 있는 DLL을 별도의 AppDomain을 만들어 그 안에서 로드한 다음 리플렉션을 이용해 '확장 컨트롤 규약'을 만족하는지 확인하는 용도로 사용하곤 합니다. 이렇게 밖에 할 수 없는 이유는, DLL이 AppDomain 별로 로드/언로드가 가능하기 때문입니다. 따라서 만약 별도의 AppDomain을 만들지 않고, 현재의 AppDomain에서 /extension 폴더에 포함된 DLL을 로드해 버리면 그것이 '확장 컨트롤 규약'을 만족하지 않아도 언로드할 수 없으므로 계속 들고 있게 됩니다. (해당 파일이 잠기는 것은 덤으로 따라오는 고통입니다.)

이런저런 이유로, AppDomain은 알아두면 꽤나 유용한데요. 문제는, AppDomain은 '격리 공간'이기 때문에 하나의 동일한 어셈블리라고 해도 각각의 AppDomain에 모두 로드되어야 한다는 단점이 있습니다. 당연하겠지만, 이렇게 되면 동일한 DLL을 AppDomain 별로 가져야 하기 때문에 JIT 컴파일을 비롯해서 메모리 공간의 낭비로 이어집니다. 마이크로소프트는 이런 단점을 해결하기 위해 3가지 유형의 어셈블리 공유 방식을 CLR 수준에서 지원합니다.

  • SingleDomain (기본값): mscorlib.dll을 제외한 모든 어셈블리를 개별 AppDomain에 로드한다. mscorlib.dll은 SharedDomain에 로드되고 다른 AppDomain들은 SharedDomain에 로드된 mscorlib.dll을 공유한다.

  • MultiDomainHost (ASP.NET 웹 응용 프로그램의 기본값): mscorlib.dll뿐만 아니라 GAC에 등록된 어셈블리를 모두 SharedDomain에 로드해 공유한다. 그 이외의 어셈블리들은 모두 개별 AppDomain에 로드한다. 과거에 닷넷 1.x 환경의 경우, GAC에 등록되어 있지 않았더라도 강력한 이름의 어셈블리(strong-named assembly)라면 모두 SharedDomain에 로드했지만 2.0부터는 GAC의 어셈블리만으로 정책이 변경됨.

  • MultiDomain: 모든 어셈블리를 SharedDomain에 로드하고 공유한다.

즉, SharedDomain에 공유할 어셈블리를 보관할 수 있게 해서 AppDomain 마다 중복 로드되는 문제를 해결한 것입니다. 그리고, 이렇게 SharedDomain에 보관되는 어셈블리를 일컬어 "도메인 중립적인 어셈블리(Domain neutral assembly)"라고 부릅니다.

재미있는 것은, 어셈블리 스스로는 도메인 중립적으로 로드하라고 명시할 수 없다는 점입니다. 단지, 도메인 중립적으로 로드할지에 대한 정책이 AppDomain에 지정되는 것입니다.

참고로, 이 값들은 mscorlib.dll에 다음과 같이 정의되어 있습니다.

namespace System
{
    using System.Runtime.InteropServices;
    
    [Serializable, ComVisible(true)]
    public enum LoaderOptimization
    {
        [Obsolete("This method has been deprecated. Please use Assembly.Load() instead. http://go.microsoft.com/fwlink/?linkid=14202")]
        DisallowBindings = 4,
        [Obsolete("This method has been deprecated. Please use Assembly.Load() instead. http://go.microsoft.com/fwlink/?linkid=14202")]
        DomainMask = 3,
        MultiDomain = 2,
        MultiDomainHost = 3,
        NotSpecified = 0,
        SingleDomain = 1
    }
}

사실상 쓰는 값은 SingleDomain = 1, MultiDomain = 2, MultiDomainHost = 3 입니다.




그럼, 재미있는 코딩과 함께 직접 눈으로 확인을 해볼까요? ^^

이를 위해 LoaderOptimization 모드를 지정할 수 있는 방법을 사용해야 하는데 크게 다음의 3가지 방식이 있습니다.


이 중에서 가장 쉬운 방법은 첫 번째 방법이므로, 저 역시 예제를 간단히 하기 위해 그것을 사용하겠습니다.

우선, 콘솔 프로그램을 하나 만들고 다음과 같이 Main 메서드를 작성합니다.

using System;

namespace ConsoleApplication1
{
    partial class Program
    {
        [LoaderOptimization(LoaderOptimization.SingleDomain)]
        static void Main(string[] args)
        {
            Console.WriteLine(AppDomain.CurrentDomain.SetupInformation.LoaderOptimization); // 출력 결과: SingleDomain
        }
    }
}

기본값이 LoaderOptimization.SingleDomain이어서 지정하지 않아도 되지만 어쨌든 명시를 했습니다. 그리고 SharedDomain에 보관되는 DLL을 확인하기 위해 라이브러리 프로젝트를 2개 만드는데요. 하나는 일반 DLL로, 다른 하나는 GAC에 등록되는 강력한 이름을 가진 DLL로 만듭니다.

  • ConsoleApplication1: 콘솔 프로그램, StrongDLL과 WeakDLL 라이브러리를 참조
  • StrongDLL: GAC에 등록해서 테스트할 목적의 DLL 라이브러리 (빌드 후, GAC 등록)
  • WeakDLL: GAC에 등록되지 않는 일반 DLL 라이브러리

Main 메서드 내의 코드는 테스트를 위해 AppDomain을 하나 만들고 다음과 같이 채워줍니다.

[LoaderOptimization(LoaderOptimization.SingleDomain)]
static void Main(string[] args)
{
    new StrongDLL.Class1().DoMethod();  // "StrongDLL.Class1.DoMethod called" 문자열 출력 코드 포함
    new WeakDLL.Class1().DoMethod();    // "WeakDLL.Class1.DoMethod called" 문자열 출력 코드 포함

    // AppDomain에 로드된 어셈블리 목록 출력
    WeakDLL.Class1.DisplayAssemblies(AppDomain.CurrentDomain);

    AppDomain appDomain = AppDomain.CreateDomain("TestAppDomain 1");
    appDomain.DoCallBack(
        () =>
        {
            // 이하 코드는 생성된 "TestAppDomain 1" 내에서 수행됨.

            new StrongDLL.Class1().DoMethod();  // "StrongDLL.Class1.DoMethod called" 문자열 출력 코드 포함
            new WeakDLL.Class1().DoMethod();    // "WeakDLL.Class1.DoMethod called" 문자열 출력 코드 포함

            // AppDomain에 로드된 어셈블리 목록 출력
            WeakDLL.Class1.DisplayAssemblies(AppDomain.CurrentDomain);
        }
    );

    Console.WriteLine("Press any key to exit...");
    Console.ReadLine();
}

즉, Main 메서드가 포함된 Default Domain (콘솔의 경우 AppDomain 이름이 실행 파일명)과 새롭게 생성한 "TestAppDomain 1"에서 DLL 2개를 사용하고 있습니다.

일단, 저 상태에서 실행해 보면 다음과 같은 출력 결과를 볼 수 있습니다.

StrongDLL.Class1.DoMethod called
WeakDLL.Class1.DoMethod called
[ConsoleApplication1.exe]
        mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
        StrongDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=677c36b6f45d74b0
        WeakDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
        System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

StrongDLL.Class1.DoMethod called
WeakDLL.Class1.DoMethod called
[TestAppDomain 1]
        mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
        ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
        StrongDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=677c36b6f45d74b0
        WeakDLL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

아쉽게도 AppDomain.GetAssemblies() 메서드의 결과로는 해당 AppDomain에 올라온 DLL 목록만을 볼 수 있을 뿐, SharedDomain 관련 여부는 알 수 없습니다. 따라서 그 부분을 파악하고 싶다면 windbg.exe와 sos.dll 확장의 도움을 받아야 합니다.

다음은 SingleDomain 유형으로 설정되었을 때의 !dumpdomain 상황을 보여줍니다.

0:007> .loadby sos clr

0:007> !dumpdomain
--------------------------------------
System Domain:      00007ffb1707dcf0
LowFrequencyHeap:   00007ffb1707e268
HighFrequencyHeap:  00007ffb1707e2f8
StubHeap:           00007ffb1707e388
Stage:              OPEN
Name:               None
--------------------------------------
Shared Domain:      00007ffb1707d720
LowFrequencyHeap:   00007ffb1707e268
HighFrequencyHeap:  00007ffb1707e2f8
StubHeap:           00007ffb1707e388
Stage:              OPEN
Name:               None
Assembly:           000001acdb1fbd70 [C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        000001acdb1e4d50
  Module Name
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

--------------------------------------
Domain 1:           000001acdb18ae60
LowFrequencyHeap:   000001acdb18b658
HighFrequencyHeap:  000001acdb18b6e8
StubHeap:           000001acdb18b778
Stage:              OPEN
SecurityDescriptor: 000001acdb18ce80
Name:               ConsoleApplication1.exe
Assembly:           000001acdb1fbd70 [C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        000001acdb1e4d50
SecurityDescriptor: 000001acdb1f2f50
  Module Name
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly:           000001acdb1fab70 [C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe]
ClassLoader:        000001acdb209dd0
SecurityDescriptor: 000001acdb1f2c80
  Module Name
00007ffab70440c0            C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe

Assembly:           000001acdb1faed0 [C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll]
ClassLoader:        000001acdb20db80
SecurityDescriptor: 000001acdb1f3400
  Module Name
00007ffab7045b80            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll

Assembly:           000001acdb1fb7d0 [C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll]
ClassLoader:        000001acdb20dc30
SecurityDescriptor: 000001acdb1f3130
  Module Name
00007ffab70463a8            C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll

Assembly:           000001acdb1fb110 [C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll]
ClassLoader:        000001acdb21e630
SecurityDescriptor: 000001acdb1f2d70
  Module Name
00007ffb0b521000            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll

--------------------------------------
Domain 2:           000001acdb215e80
LowFrequencyHeap:   000001acdb216678
HighFrequencyHeap:  000001acdb216708
StubHeap:           000001acdb216798
Stage:              OPEN
SecurityDescriptor: 000001acdb1fc320
Name:               TestAppDomain 1
Assembly:           000001acdb1fbd70 [C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
ClassLoader:        000001acdb1e4d50
SecurityDescriptor: 000001acdb1f36d0
  Module Name
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Assembly:           000001acdb1faa50 [C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe]
ClassLoader:        000001acdb230dd0
SecurityDescriptor: 000001acdb22e630
  Module Name
00007ffab71a5308            C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe

Assembly:           000001acdb1fb8f0 [C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll]
ClassLoader:        000001acdb2332e0
SecurityDescriptor: 000001acdb22f800
  Module Name
00007ffab71a5c88            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll

Assembly:           000001acdb1fbb30 [C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll]
ClassLoader:        000001acdb229110
SecurityDescriptor: 000001acdb22e270
  Module Name
00007ffab71a64b0            C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll

LoaderOptimization.SingleDomain 모드에서는 mscorlib.dll만 SharedDomain에 로드되고 나머지 어셈블리들은 각자의 AppDomain에 중복 로드된다고 했습니다. 정말 그렇게 나오는지 mscorlib.dll을 뽑아서 살펴보면,

Shared Domain:      00007ffb1707d720
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Domain 1:           000001acdb18ae60
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

Domain 2:           000001acdb215e80
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

mscorlib.dll의 모듈 주소가 00007ffb042d1000로 동일하게 나옵니다. 게다가 SharedDomain 목록에 포함된 것은 mscorlib.dll만이 유일합니다.




이번에는, 모든 DLL을 SharedDomain으로 올리는 LoaderOptimization.MultiDomain 모드를 테스트하기 위해 Main 메서드에 지정된 특성을 다음과 같이 바꾸고

[LoaderOptimization(LoaderOptimization.MultiDomain)]
static void Main(string[] args)
{
    // ...[생략]...
}

실행한 후 windbg의 !dumpdomain 출력 결과를 (System Domain 제외, 약간 정리해서) 보면,

--------------------------------------
Shared Domain:      00007ffb1707d720
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
00007ffab7004178            C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
00007ffb0b521000            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
00007ffab7004e98            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll
00007ffab7005570            C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll

--------------------------------------
Domain 1:           0000016c3663ac70
Name:               ConsoleApplication1.exe
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
00007ffab7004178            C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
00007ffb0b521000            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
00007ffab7004e98            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll
00007ffab7005570            C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll

--------------------------------------
Domain 2:           0000016c366c9060
Name:               TestAppDomain 1
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
00007ffab7004178            C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
00007ffb0b521000            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
00007ffab7004e98            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll
00007ffab7005570            C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll

예상했던 대로 사용중인 모든 DLL들이 Shared Domain에 올라와 있고 개별 AppDomain에 표시된 모든 DLL들의 모듈 주소가 같습니다. (즉, 공유되었습니다.)

마지막으로 GAC에 등록된 어셈블리만을 SharedDomain으로 올리는 LoaderOptimization.MultiDomainHost 모드를 테스트 해보겠습니다.

[LoaderOptimization(LoaderOptimization.MultiDomainHost)]
static void Main(string[] args)
{
    // ...[생략]...
}

--------------------------------------
Shared Domain:      00007ffb1707d720
00007ffb0b521000            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll
00007ffab7024780            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll

--------------------------------------
Domain 1:           000002482958ae60
Name:               ConsoleApplication1.exe
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
00007ffab70340c0            C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
00007ffab7024780            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll
00007ffab7035cb8            C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll
00007ffb0b521000            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll

--------------------------------------
Domain 2:           000002482961c280
Name:               TestAppDomain 1
00007ffb042d1000            C:\WINDOWS\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
00007ffab7195308            C:\shared_domain\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe
00007ffab7024780            C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\StrongDLL\v4.0_1.0.0.0__677c36b6f45d74b0\StrongDLL.dll
00007ffab7195dc0            C:\shared_domain\ConsoleApplication1\bin\Debug\WeakDLL.dll

문서와 동일하게, GAC에 등록된 어셈블리만 Shared Domain에 목록이 올라와 있고 그 외의 어셈블리들은 개별 AppDomain에 있습니다. 그래서 같은 사용자 DLL이지만, StrongDLL.dll은 SharedDomain에 포함된 반면, WeakDLL.dll은 개별 AppDomain에 로드된 것입니다.

(첨부한 파일은 이 글의 예제 코드를 포함합니다.)




아울러, 다음의 문서도 읽어보실 것을 권장합니다. ^^

Application Domains
; https://learn.microsoft.com/en-us/dotnet/framework/app-domains/application-domains

Domain Neutral Assemblies
; https://learn.microsoft.com/en-us/archive/blogs/junfeng/domain-neutral-assemblies




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 2/27/2024]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2016-05-20 02시58분
지난번에 ContextBindingObject 이야기를 하실 때 제가 사용하고 있다고 말씀드렸더니...우려를 표하셨었죠.^^ ("https://www.sysnet.pe.kr/2/0/10901#11621")
AppDomain도 사용하고 있는데 정말 잘못하면 지옥을 맛볼 수 있는 주제가 아닌가 싶습니다.
DLL을 동적 바인딩으로 처리하다가 결국 여러차례 같은 부분을 실행하면 OOM 이 발생하기에 상황도 모르고 AppDomain으로 분리해보는게 어떻냐고 조언(?)을 했다가 1년째 문제 생기면 끌려가서 해결하고 있습니다.
10년째 유지보수되고 있는 비대한 코드를 가지고 있는데 static 형태로 전역변수(?) 변수를 많이 사용하는 어플리케이션에서는 답이 안나오더라구요.
덕분에 절대 AppDomain이 적용되지 말아야 할 코드는 어떤것인지 몸으로 체험하게 되었지만...오늘도 분리된 다중 도메인에서의 변수 공유(어울리지 않네요 AppDomain과 값 공유라니)문제로 하루를 보내게 될 것 같습니다. 어설프게 알면서 참견했던 제가 바보같습니다.ㅜㅜ
Beren Ko
2016-05-20 01시58분
자신의 책임하에 항상 둘 수 있는 솔루션 개발이라면 기술적이거나 실험적인 코드를 넣어도 괜찮을 수 있는데... SI처럼 치고 빠져야 할 성격의 프로젝트에는 조심스럽게 해야 하는 것 같습니다. 그렇다고는 해도, 어쨌든 현장에서의 문제를 해결하려면 어떤 트릭이 요구되는 경우가 종종 있으니 정답은 없는 것 같습니다. ^^
정성태
2016-05-24 04시39분
[Beren Ko] 그렇게 말씀해주시니 약간 위로를 받은 기분이...^^ 감사합니다.
[guest]

... 46  47  48  49  50  51  52  53  54  55  56  [57]  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12191정성태3/14/202012224개발 환경 구성: 483. docker - OracleXE 컨테이너 실행 [1]
12190정성태3/14/20208419오류 유형: 606. Docker Desktop 업그레이드 시 "The process cannot access the file 'C:\Program Files\Docker\Docker\resources\dockerd.exe' because it is being used by another process."
12189정성태3/13/202013215개발 환경 구성: 482. Facebook OAuth 처리 시 상태 정보 전달 방법과 "유효한 OAuth 리디렉션 URI" 설정 규칙
12188정성태3/13/202015337Windows: 169. 부팅 시점에 실행되는 chkdsk 결과를 확인하는 방법
12187정성태3/12/20208177오류 유형: 605. NtpClient was unable to set a manual peer to use as a time source because of duplicate error on '...'.
12186정성태3/12/20209269오류 유형: 604. The SysVol Permissions for one or more GPOs on this domain controller and not in sync with the permissions for the GPOs on the Baseline domain controller.
12185정성태3/11/20209897오류 유형: 603. The browser service was unable to retrieve a list of servers from the browser master...
12184정성태3/11/202011376오류 유형: 602. Automatic certificate enrollment for local system failed (0x800706ba) The RPC server is unavailable. [3]
12183정성태3/11/20209703오류 유형: 601. Warning: DsGetDcName returned information for \\[...], when we were trying to reach [...].
12182정성태3/11/202010951.NET Framework: 901. C# Windows Forms - Vista/7 이후의 Progress Bar 업데이트가 느린 문제파일 다운로드1
12181정성태3/11/202011822기타: 76. 재현 가능한 최소한의 예제 프로젝트란? - 두 번째 예제파일 다운로드1
12180정성태3/10/20208414오류 유형: 600. "Docker Desktop for Windows" - EXPOSE 포트가 LISTENING 되지 않는 문제
12179정성태3/10/202019770개발 환경 구성: 481. docker - PostgreSQL 컨테이너 실행
12178정성태3/10/202011213개발 환경 구성: 480. Linux 운영체제의 docker를 위한 tcp 바인딩 추가 [1]
12177정성태3/9/202010895개발 환경 구성: 479. docker - MySQL 컨테이너 실행
12176정성태3/9/202010310개발 환경 구성: 478. 파일의 (sha256 등의) 해시 값(checksum) 확인하는 방법
12175정성태3/8/202010399개발 환경 구성: 477. "Docker Desktop for Windows"의 "Linux Container" 모드를 위한 tcp 바인딩 추가
12174정성태3/7/20209948개발 환경 구성: 476. DockerDesktopVM의 파일 시스템 접근 [3]
12173정성태3/7/202010968개발 환경 구성: 475. docker - SQL Server 2019 컨테이너 실행 [1]
12172정성태3/7/202015801개발 환경 구성: 474. docker - container에서 root 권한 명령어 실행(sudo)
12171정성태3/6/202010753VS.NET IDE: 143. Visual Studio - ASP.NET Core Web Application의 "Enable Docker Support" 옵션으로 달라지는 점 [1]
12170정성태3/6/20209401오류 유형: 599. "Docker Desktop is switching..." 메시지와 DockerDesktopVM CPU 소비 현상
12169정성태3/5/202011443개발 환경 구성: 473. Windows nanoserver에 대한 docker pull의 태그 사용 [1]
12168정성태3/5/202012092개발 환경 구성: 472. 윈도우 환경에서의 dockerd.exe("Docker Engine" 서비스)가 Linux의 것과 다른 점
12167정성태3/5/202011349개발 환경 구성: 471. C# - 닷넷 응용 프로그램에서 DB2 Express-C 데이터베이스 사용 (3) - ibmcom/db2express-c 컨테이너 사용
12166정성태3/4/202011028개발 환경 구성: 470. Windows Server 컨테이너 - DockerMsftProvider 모듈을 이용한 docker 설치
... 46  47  48  49  50  51  52  53  54  55  56  [57]  58  59  60  ...