15. Box의 크기
⚫ Boxing이 발생하면 메모리를 얼마나 차지할까?
⚫ 값 타입의 최소 크기는 4 byte
⚫ 참조 타입의 최소 크기 12 byte
▪ 32bit System 기준
⚫ Equals() 호출시 Boxing 2번 발생
⚫ 총 24 Byte 사용
⚫ 한 프레임에 40번 비교하면 24 x 40 ~= 1 Kbyte Gabage 발생
24. Generic Enum 과 Int 사이의 변환
⚫ Enum은 그저 숫자에 불과하다.
▪ BackField 타입을 지정할 수 있다.
▪ 아무것도 없으면 int
⚫ Int 로 변환할 수 있다면 Boxing 없이 비교할 수 있다.
▪ 일반화된 Bitmasking처리도 가능하다.
25. Generic Enum 과 Int 사이의 변환
⚫ 개별적인 Enum타입은 쉽게 int 로 변환할 수 있다.
⚫ Generic 으로 받은 Enum은 변환이 어렵다.
⚫ 방법을 찾아보자.
27. 동적 코드생성
⚫ 개별적인 Enum타입은 쉽게 int 로 변환할 수 있다.
⚫ Generic 으로 받은 Enum은 변환이 어렵다.
⚫ Generic 타입의 구체타입이 무엇이 될것인지
컴파일 시점에서는 확정할 수 없기 때문.
⚫ 프로그램이 실행되는 중에는 구체적인 타입이 무엇인지 알고 있다.
⚫ 즉시 코드를 생성해서 변환한다.
28. 동적 코드생성
⚫ 런타임에 개별 enum 타입을 캐스팅하는 코드를 생성한다.
* ValueCastTo<TTo> 클래스로 분리하지 않으면 유니티 구버전에서는 컴파일 에러가 발생한다.
29. 동적 코드생성
⚫ 사용법
⚫ 동적 코드 생성이라니, 기술 그 자체로 멋있다!
⚫ 문제 해결!
⚫ 하지만 AOT(Ahead Of Time) 플랫폼에서 동작하지 않는다.
▪ 망해라 애플
31. C++ Union 트릭
⚫ C#의 조상언어인 C++에는 Union 타입이 존재한다.
⚫ Union에 선언된 필드는 같은 메모리를 액세스한다.
⚫ C#은 Union 타입을 지원하지 않지만
[StructLayout], [FieldOffset] 특성을 사용하여 흉내낼 수 있다.
33. C++ Union 트릭
⚫ 잘 동작한다!
⚫ 성능도 너무 좋다!
⚫ 그런데 강타입 언어가 이렇게 쉽게 타입체크를 우회해도 되나?
34. C++ Union 트릭
⚫ 런타임 구현에 따라 다르다.
⚫ .Net 3.5 Equivalent 에서는 잘 동작
▪ 내부적으로 Mono 2.6.5 런타임 사용
⚫ .Net 4.x Equivalent에서는 부작용 존재
▪ 내부적으로 Mono 4.2.2 런타임 사용
⚫ 이 기법을 적용한 Assembly에 Reflection을 시도하면 예외가 발생한다.
▪ System.TypeLoadException: Generic class cannot have explicit layout.
38. Unsafe Pointer 트릭
⚫ 잘 동작한다.
⚫ 컴파일시 -unsafe 스위치가 있어야 컴파일이 가능하다.
⚫ Unity2017.x 에서는 unsafe 가 디폴트
⚫ Unity2018.x 에서는 설정에서 선택가능
* 유니티 구버전에서 unsafe 플래그를 지정하려면 Assets 폴더에 mcs.rsp, csc.rsp 파일을 생성하고 내용에 -unsafe 를 추가한다.
42. EnumDictionary
⚫ #if 를 사용해서 플랫폼에 따라 구현을 선택한다.
⚫ 기본적으로 동적 코드생성을 사용
⚫ Unity 환경에서는
⚫ .Net 3.5 에서는 C++ Union 트릭사용
⚫ .Net 4.x 에서는 Unsafe Pointer 트릭사용
▪ 2018.x 버전에서는 allow unsafe code 옵션을 켜고 쓴다.
44. EnumDictionary
⚫ 전체 코드
▪ https://github.com/netics01/EnumDictionary
⚫ BitConvert
▪ 모든 Enum 과 Int 변환방식 구현
⚫ EnumDictionary
⚫ EnumHashSet
⚫ 데브캣에서 사용하는 SUF의 일부
▪ Silvervine Unity Framework
* 64bit BackField 를 사용하는 Enum 에는 사용할 수 없다.