Microsoft MVP성태의 닷넷 이야기
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 11개 있습니다.)

(번역글) .NET Internals Cookbook Part 12 - Memory structure, attributes, handles

드디어 .NET Internals Cookbook 시리즈의 12번째 마지막 글입니다. ^^

(번역글) .NET Internals Cookbook Part 1 - Exceptions, filters and corrupted processes
; https://www.sysnet.pe.kr/2/0/11838

(번역글) .NET Internals Cookbook Part 2 - GC-related things
; https://www.sysnet.pe.kr/2/0/11869

(번역글) .NET Internals Cookbook Part 3 - Initialization tricks
; https://www.sysnet.pe.kr/2/0/11871

(번역글) .NET Internals Cookbook Part 4 - Type members
; https://www.sysnet.pe.kr/2/0/11872

(번역글) .NET Internals Cookbook Part 5 - Methods, parameters, modifiers
; https://www.sysnet.pe.kr/2/0/11873

(번역글) .NET Internals Cookbook Part 6 - Object internals
; https://www.sysnet.pe.kr/2/0/11874

(번역글) .NET Internals Cookbook Part 7 - Word tearing, locking and others
; https://www.sysnet.pe.kr/2/0/11876

(번역글) .NET Internals Cookbook Part 8 - C# gotchas
; https://www.sysnet.pe.kr/2/0/11877

(번역글) .NET Internals Cookbook Part 9 - Finalizers, queues, card tables and other GC stuff
; https://www.sysnet.pe.kr/2/0/11878

(번역글) .NET Internals Cookbook Part 10 - Threads, Tasks, asynchronous code and others
; https://www.sysnet.pe.kr/2/0/11879

(번역글) .NET Internals Cookbook Part 11 - Various C# riddles
; https://www.sysnet.pe.kr/2/0/11882

.NET Internals Cookbook Part 12 - Memory structure, attributes, handles
; https://blog.adamfurmanek.pl/2019/05/04/net-internals-cookbook-part-12/





82. 속성의 3가지 분류 - bit-mapped, custom, pseudo-custom

속성은 IL 언어와의 관계에서 3가지로 분류됩니다.

  1. Bit-mapped - C# 언어의 속성이 그대로 IL과 1:1 매핑되는 경우, 예를 들어 public
  2. Custom - 일반적인 특성, 예를 들어 사용자가 정의한 모든 특성
  3. Pseudo-custom - Custom 특성과 유사하지만 IL에 반영되는 특성, 예를 들어 Serializable

이해를 돕기 위해 C# 코드와 그것의 IL 코드 번역을 보겠습니다.

using System;

[MyCustom]
[Serializable]
public class Program
{
    public static void Main()
    {
    }
}

class MyCustomAttribute : Attribute
{
    public MyCustomAttribute() { }
}

위에서 Program 타입에 지정한 MyCustom, Serializable, public 속성은 IL 코드에 다음과 같이 반영됩니다.

.class public auto ansi serializable beforefieldinit Program
	extends [mscorlib]System.Object
{
	.custom instance void MyCustomAttribute::.ctor() = (
        01 00 00 00
    )
	.method public hidebysig static 
		void Main () cil managed 
	{
		.maxstack 8
		.entrypoint

		IL_0000: nop
		IL_0001: ret
	} // end of method Program::Main

	.method public hidebysig specialname rtspecialname 
		instance void .ctor () cil managed 
	{
		.maxstack 8

		IL_0000: ldarg.0
		IL_0001: call instance void [mscorlib]System.Object::.ctor()
		IL_0006: nop
	} // end of method Program::.ctor

} // end of class Program

보는 바와 같이 public은 public으로 직접 매핑되므로 bit-mapped, C#의 클래스로 정의된 Serializable은 serializable로 지정되기 때문에 Pseudo-custom으로, MyCustom의 경우 IL 예약어로 번역되지 않고 ".custom instance void MyCustomAttribute::.ctor()"라는 별도 항목을 갖기 때문에 Custom으로 분류됩니다.

Pseudo-custom에 대한 보다 자세한 사항은 다음의 글을 참고하세요.

Subterranean IL: Pseudo custom attributes
; https://www.red-gate.com/simple-talk/blogs/subterranean-il-pseudo-custom-attributes/





83. 핸들 재사용 공격이란?

윈도우의 HANDLE은 프로세스(EXE)가 소유한 핸들 테이블에 대한 인덱스 번호입니다. 그렇다면, A라는 스레드가 Handle 값을 스택에 보관하고 스레드가 중지(suspend)되었다고 가정해 보겠습니다. 그때 다른 B 스레드가 해당 핸들을 닫아버리고(CloseHandle) 새로운 커널 객체를 생성하면 이전에 닫았던 동일한 핸들(인덱스 번호)이 재사용되는 것도 가능합니다. 만약 그런 상황이 발생했을 때 A 스레드가 다시 실행을 재개(resume), 스택에 보관했던 핸들을 사용하게 되면 의도치 않는 커널 자원을 사용하게 됩니다.





84. .NET 세계에서의 Handle 자원의 종류는?

  • Strong handle - 일반적인 참조(like a normal reference)
  • Short weak handle - GC되는 것을 막지도 못하고 되살아난 경우에도 그것을 알수 없음(doesn’t stop the object from cleaning up, does not track the object if it is resurrected)
  • Long weak handle - "Short weak handle"처럼 GC되는 것을 막지는 못하지만 되살아난 경우에는 알 수 있음(like short weak handle but tracks the object after it gets resurrected)
  • Pinned handle - GC 도중 객체를 움직이지 못하도록 함(strong handle which doesn’t allow the object to be moved)
  • Async pinned handle - Pinned 핸들과 같지만 GC는 해당 핸들이 async 동작 후 unpinned시킬 수 있다는 것을 알고 있음(like pinned handle but GC knows that it can be unpinned after async (typically I/O) operation is completed)
  • Ref count handle - COM 연동 시처럼 그것의 참조 카운트가 유지되는 유형의 핸들(handle counting references, used for COM interop)
  • Dependent handle - ConditionalWeakTable에 사용되는데, 2개의 객체를 strong handle로 연결하지만 외부적으로는 weak handle임(used by ConditionalWeakTable, connects two objects by strong handle, but from the outside is like a weak handle)


아래는 windbg에서 devenv.exe를 대상으로 !gchandles를 수행한 경우의 결과를 보여줍니다.

0:000> !gchandles
...[생략]...
Total 62730 objects

Handles:
    Strong Handles:       217
    Pinned Handles:       134
    Async Pinned Handles: 66
    Ref Count Handles:    1240
    Weak Long Handles:    2410
    Weak Short Handles:   55019
    Dependent Handles:    3644





85. ref local이란?

제 책에서 C# 7.0의 "12.2 반환값 및 로컬 변수에 ref 기능 추가(ref returns and locals)"를 참고하세요. ^^





86. interior pointer란?

예전에 Span을 설명하면서 interior pointer를 소개한 적이 있습니다.

C# 7.2 - Span<T>
; https://www.sysnet.pe.kr/2/0/11534

"interior pointer"는 객체의 내부를 가리키는 관리 포인터입니다. 예를 들어 다음의 코드를 보면,

using System;

namespace Program
{
    public class Program
    {   
        public static void Main(string[] args)
        {
            var foo = new Foo();
            foo.Bar = 5;
            ref int bar = ref foo.Bar;
            
            Console.WriteLine(foo.Bar);
            Console.WriteLine(bar);
            
            foo.Bar = 6;
            Console.WriteLine(foo.Bar);
            Console.WriteLine(bar);
            
            bar = 7;
            Console.WriteLine(foo.Bar);
            Console.WriteLine(bar);
        }
    }
}

class Foo{
    public int Bar;
}

foo 변수는 GC 힙 메모리 위치에서 Foo 타입의 인스턴스를 가리키고 있는 반면, bar 변수는 foo 변수의 위치가 아닌, 그 객체의 내부에 "int Bar" 필드의 위치를 가리키는 관리 포인터입니다. 유의할 것은, 같은 ref 지역 변수를 사용하는 구문이지만 어떤 것을 가리키느냐에 따라 interior pointer가 아닐 수도 있다는 점입니다.

// interior pointer인 경우 
ref int bar = ref foo.Bar; // foo 객체의 내부를 가리키므로 interior pointer

// interior pointer가 아닌 경우
int a = 5;
ref int bar = ref a; // 스택에 있는 로컬 변수를 가리키므로 interior pointer가 아님

그렇다면, GC는 interior pointer의 참조로 인해 해당 객체를 제거해서는 안 된다는 것을 어떻게 알 수 있을까요? 이를 위해 힙 영역을 다중 블록으로 나눈 Brick table이라는 것을 사용합니다. It contains an offset to the first object inside such a block so then it can traverse the chunk of memory and find the object which should be held by the interior pointer. 하지만 이 작업은 성능상 매우 좋지 않기 때문에 interior pointer는 스택에 존재하는 로컬 변수 반환 값으로만 사용하도록 제한되었습니다. 즉, 힙에 할당되는 클래스의 경우에는 다음과 같이 interior pointer를 포함하지 못합니다.

class Foo{
    public ref int Bar;
}





87. ref struct란?

다음의 글을 참고하세요.

C# 7.2 - 스택에만 생성할 수 있는 값 타입 지원 - "ref struct"
; https://www.sysnet.pe.kr/2/0/11530





88. unsafe struct란?

사실 "unsafe struct"라는 아주 새로운 유형의 구조체가 있는 것은 아니고, 단지 내부에 unsafe 관련 코드가 사용되면 붙여야 하는 것뿐입니다.

class Program
{
    public int i;

    public static void Main()
    {
    }
}

unsafe struct Vector
{
    public /* 또는 여기서 unsafe를 붙이거나 */ void Do()
    {
        Program pg = new Program();

        /* 또는 여기서 unsafe block을 붙이거나 */
        fixed (int* ptr = &pg.i)
        {
        }
    }
}

단지 원 글에서는 fixed size buffer 사용 구문을 사용하는 경우,

unsafe struct FixedBufferExample
{
    public fixed int buffer[1024]; // This is a fixed buffer.
}

unsafe를 struct 수준에서만 붙일 수 있다는 특수성이 있는 것입니다.





89. readonly struct란?

다음의 글을 참고하세요.

C# 7.2 - readonly 구조체
; https://www.sysnet.pe.kr/2/0/11524





90. unsafe 타입이란?

원 글에서는 unsafe 코드를 사용하는 클래스라고 하지만 위에서 설명했듯이 struct에도 붙일 수 있으므로 "클래스 및 구조체"라고 확장해서 정의할 수 있습니다.





91. blittable 타입이란?

다음의 글을 참고하세요.

C# - blittable 타입이란?
; https://www.sysnet.pe.kr/2/0/11557

C# 7.3 - unmanaged(blittable) 제네릭 제약
; https://www.sysnet.pe.kr/2/0/11558





92. C++/CLI에서 비관리 class는 어떤 식으로 컴파일될까?

ref class와 unmanaged class를 사용하는 다음의 C++/CLI 코드를 빌드해 보면,

#include "stdafx.h"
#include <cstdio>

using namespace System;

ref class Foo {
};

class Bar {
};

void Baz() {
    System::Console::WriteLine("In managed function.");
}

#pragma managed(push, off)
void Taz() {
    printf("In unmanaged function.\n");
}

#pragma managed(pop)

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Hello World");
    return 0;
}

ref class Foo 타입과 관리 코드를 포함하는 Baz, main 함수는 IL 코드로 번역이 되는 반면, 비관리 코드만을 포함한 Taz 함수와 class Bar는 C++ 함수로 번역되므로 IL 코드로 남지 않습니다.



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

[연관 글]






[최초 등록일: ]
[최종 수정일: 10/27/2022]

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

비밀번호

댓글 작성자
 




1  2  3  4  5  6  [7]  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13449정성태11/21/20232351개발 환경 구성: 688. Azure OpenAI 서비스 신청 방법
13448정성태11/20/20232626닷넷: 2163. .NET 8 - Dynamic PGO를 결합한 성능 향상파일 다운로드1
13447정성태11/16/20232486닷넷: 2162. ASP.NET Core 웹 사이트의 SSL 설정을 코드로 하는 방법
13446정성태11/16/20232419닷넷: 2161. .NET Conf 2023 - Day 1 Blazor 개요 정리
13445정성태11/15/20232699Linux: 62. 리눅스/WSL에서 CA 인증서를 저장하는 방법
13444정성태11/15/20232455닷넷: 2160. C# 12 - Experimental 특성 지원
13443정성태11/14/20232492개발 환경 구성: 687. OpenSSL로 생성한 사용자 인증서를 ASP.NET Core 웹 사이트에 적용하는 방법
13442정성태11/13/20232321개발 환경 구성: 686. 비주얼 스튜디오로 실행한 ASP.NET Core 사이트를 WSL 2 인스턴스에서 https로 접속하는 방법
13441정성태11/12/20232652닷넷: 2159. C# - ASP.NET Core 프로젝트에서 서버 Socket을 직접 생성하는 방법파일 다운로드1
13440정성태11/11/20232352Windows: 253. 소켓 Listen 시 방화벽의 Public/Private 제어 기능이 비활성화된 경우
13439정성태11/10/20232844닷넷: 2158. C# - 소켓 포트를 미리 시스템에 등록/예약해 사용하는 방법(Port Exclusion Ranges)파일 다운로드1
13438정성태11/9/20232462닷넷: 2157. C# - WinRT 기능을 이용해 윈도우에서 실행 중인 Media App 제어
13437정성태11/8/20232656닷넷: 2156. .NET 7 이상의 콘솔 프로그램을 (dockerfile 없이) 로컬 docker에 배포하는 방법
13436정성태11/7/20232893닷넷: 2155. C# - .NET 8 런타임부터 (Reflection 없이) 특성을 이용해 public이 아닌 멤버 호출 가능
13435정성태11/6/20232828닷넷: 2154. C# - 네이티브 자원을 포함한 관리 개체(예: 스레드)의 GC 정리
13434정성태11/1/20232618스크립트: 62. 파이썬 - class의 정적 함수를 동적으로 교체
13433정성태11/1/20232341스크립트: 61. 파이썬 - 함수 오버로딩 미지원
13432정성태10/31/20232378오류 유형: 878. 탐색기의 WSL 디렉터리 접근 시 "Attempt to access invalid address." 오류 발생
13431정성태10/31/20232707스크립트: 60. 파이썬 - 비동기 FastAPI 앱을 gunicorn으로 호스팅
13430정성태10/30/20232597닷넷: 2153. C# - 사용자가 빌드한 ICU dll 파일을 사용하는 방법
13429정성태10/27/20232856닷넷: 2152. Win32 Interop - C/C++ DLL로부터 이중 포인터 버퍼를 C#으로 받는 예제파일 다운로드1
13428정성태10/25/20232918닷넷: 2151. C# 12 - ref readonly 매개변수
13427정성태10/18/20233085닷넷: 2150. C# 12 - 정적 문맥에서 인스턴스 멤버에 대한 nameof 접근 허용(Allow nameof to always access instance members from static context)
13426정성태10/13/20233268스크립트: 59. 파이썬 - 비동기 호출 함수(run_until_complete, run_in_executor, create_task, run_in_threadpool)
13425정성태10/11/20233084닷넷: 2149. C# - PLinq의 Partitioner<T>를 이용한 사용자 정의 분할파일 다운로드1
13423정성태10/6/20233063스크립트: 58. 파이썬 - async/await 기본 사용법
1  2  3  4  5  6  [7]  8  9  10  11  12  13  14  15  ...