Firebase 6.15 를 사용한 프로젝트를 최신버젼에서 가져와서 돌려보려 했더니 안되더라,
unity 2018 버젼을 사용해서 android export해야 되더라
그리고 혹시모르니 external dependency manager 에서 android Resolver (먼제 Delete Resolved Libraries 하고) 해주면 좋음
This is slide 1 description. Go to Edit HTML and replace these sentences with your own words. This is a Blogger template by Lasantha - PremiumBloggerTemplates.com...
This is slide 2 description. Go to Edit HTML and replace these sentences with your own words. This is a Blogger template by Lasantha - PremiumBloggerTemplates.com...
This is slide 3 description. Go to Edit HTML and replace these sentences with your own words. This is a Blogger template by Lasantha - PremiumBloggerTemplates.com...
Firebase 6.15 를 사용한 프로젝트를 최신버젼에서 가져와서 돌려보려 했더니 안되더라,
unity 2018 버젼을 사용해서 android export해야 되더라
그리고 혹시모르니 external dependency manager 에서 android Resolver (먼제 Delete Resolved Libraries 하고) 해주면 좋음
좀비슈터, 미니RPG, 등 강좌 몇개 정리해놈.
리듬게임(케이디)의 강좌도 정리해놈.
정리잘해논게 맘에듬
https://ansohxxn.github.io/categories/unity-lesson-1
https://m.blog.naver.com/PostView.nhn?blogId=hana100494&logNo=222223197400&targetKeyword=&targetRecommendationCode=1
잘정리되어 있다.
유니티관련자료가 3500 개 이다... 엄청난 놈이다.
https://baba-s.hatenablog.com/entry/2018/04/01/190000
https://qiita.com/sapphire_al2o3/items/4f517523f50e0113af1f
Unity 코드를 쓸 때 GC Alloc가 발생하는 패턴을 조사했다. GC Alloc이 줄어들 패턴 good했지만, 코드가 알기 어려울 경우도 있으므로 반드시 개서를 할 필요는 없다.
Unity 2018.4에서 동작 확인
int i = 123 ;
string s = "num_" + i ;
int i = 123 ;
string s = "num_" + i . ToString ();
string.Concat에 object로 전달되어 박스가되어 버리므로 문자열한다.
string [] num = { "0" , "1" , "2" , "3" , "4" , "5" };
// 96byte
s = num [ 0 ];
s + = num [ 1 ];
s + = num [ 2 ];
s + = num [ 3 ];
string [] num = { "0" , "1" , "2" , "3" , "4" , "5" };
// 34byte
string s = num [ 0 ] + num [ 1 ] + num [ 2 ] + num [ 3 ];
연결 할 때마다 새로운 문자열을 생성되는데, 4 개까지 연결라면 Concat (string, string, string, string)이 알려져 번에 연결 할 수있다.
var sb = new System . Text . StringBuilder ();
for ( int i = 0 ; i < num . Length ; i ++)
{
sb . Append ( num [ i ]);
}
string s = sb . ToString ();
루프에서 많은 문자열 연결 할 수 있으면 한번씩 문자열이 생성되지 않도록 StringBuilder를 사용한다.
string [] num = { "0" , "1" , "2" , "3" , "4" , "5" };
// 38byte
string s = string . Join ( "" , num );
문자열 배열을 연결하는 경우 Join을 사용한다.
string [] num = new string [ 10 ];
for ( int i = 0 ; i < num . Length ; i ++)
{
// 84byte
num [ i ] = string . Format ( "num_ {0}" , i ) ;
}
string [] num = new string [ 10 ];
for ( int i = 0 ; i < num . Length ; i ++)
{
// 64byte
num [ i ] = $ "num_ { i . ToString ()} " ;
}
string.Format보다 문자열 보간 ($ "")를 사용한다. 문자열 보간 쪽이 선명 인수가 문자열 만 있으면 간단한 문자열 연결됩니다 string.Format가 호출되지 않습니다.
var sb = new System . Text . StringBuilder ();
int n = 100 ;
sb . Append ( n );
.NET Framework에서는 정수는 ToString되어 추가된다. ToString하지 않으 문자 단위로 추가 할 필요가있다.
https://gist.github.com/sapphire-al2o3/ba7d6a80836a2e5ee117abb4c3d75132
// 40byte
EnumType e = ( EnumType ) System . Enum . ToObject ( typeof ( EnumType ), i );
// 40byte
i = System . Convert . ToInt32 ( e );
// 0byte
EnumType e = ( EnumType ) i ;
// 0byte
i = ( int ) e ;
var d = new Dictionary < EnumType , int > ();
var d = new Dictionary < int , int > ();
.NET 4라면 박스하지 않기 때문에 Enum을 Key하고 접근해서 GC Alloc는 발생하지 않지만, 저속이므로 int를 Key로하는 것이 좋다.
// 20byte
yield return 0 ;
// 0byte
yield return null ;
0을 반환하는 경우, 박스 화하여 GC Alloc가 발생한다.
IEnumrator Sum ( int [] array )
{
int s = 0 ;
foreach ( var a in array )
{
s + = a ;
yield return null ;
}
}
int [] array = { 1 , 2 , 3 , 4 , 5 };
StartCoroutine ( Sum ());
IEnumrator Sum ( int [] array )
{
int s = 0 ;
for ( int i = 0 ; i < array . Length ; i ++)
{
s + = a [ i ];
yield return null ;
}
}
int [] array = { 1 , 2 , 3 , 4 , 5 };
StartCoroutine ( Sum ());
foreach보다 for 쪽이 임시 변수가 적기 때문에 코루찐의 크기가 작아진다.
List < int > list = new List < int > ();
// 8.3Kbyte
for ( int i = 0 ; i < 1000 ; i ++)
{
list . Add ( i );
}
List < int > list = new List < int > ( 1000 );
// 4.0Kbyte
for ( int i = 0 ; i < 1000 ; i ++)
{
list . Add ( i );
}
List와 Dictionary 미리 추가하는 크기를 알고있는 경우 생성 할 때 Capacity를 지정한다.
int [] array = new int [ 100 ];
// 10.9Kbyte
for ( int i = 0 ; i < 100 ; i ++)
{
Array . Sort ( array );
}
int [] array = new int [ 100 ];
// 112byte
for ( int i = 0 ; i < 100 ; i ++)
{
Array . Sort ( array , ( x , y ) => x - y );
}
비록 int의 배열에도 람다 식을 지정하지 않으면 불필요한 캐스트가 발생 해 버린다. (.NET Core이라고 괜찮아)
void Log ( int value ) { Debug . Log ( value ); }
void Squared ( int value , Action < void > callback )
{
int v = value * 2 ;
callback ( v );
}
int [] num = { 0 , 1 , 2 , 3 , 4 };
foreach ( var n in num )
{
Squared ( n , Log );
}
void Log ( int value ) { Debug . Log ( value ); }
void Squared ( int value , Action < void > callback )
{
int v = value * 2 ;
callback ( v );
}
int [] num = { 0 , 1 , 2 , 3 , 4 };
var log = Log ;
foreach ( var n in num )
{
Squared ( n , log );
}
여러 번 호출 함수는 캐시한다.
List < int > RemoveList ( List < int > list , int v )
{
if ( list ! = null && list . Count > 0 )
{
return list . FindAll ( x => x ! = v );
}
return null ;
}
List < int > RemoveList ( List < int > list , int v )
{
if ( list ! = null && list . Count > 0 )
{
int t = v ;
return list . FindAll ( x => x ! = t );
}
return null ;
}
list가 null의 경우는 아무것도하지 않지만 bad 쪽은 함수를 호출하는 것만으로 GC Alloc가 발생한다.
함수에 들어갈 때 인수를 캡처 한 람다 표현식이 생성되어 버리기 때문에 인수를 내부의 범위에 캐싱 캡처하면 범위에 들어 가지 않는 경우는 람다 식을 생성한다.
IList list = new string [ 10 ];
foreach ( var e in list ) {}
IList list = new string [ 10 ];
for ( int i = 0 ; i < list . Count ; i ++) {}
인터페이스를 통해 foreach를 사용하면 박스가 발생하기 때문에 for를 사용한다.
// 80byte
class C
{
byte a ;
long b ;
byte c ;
long d ;
byte e ;
long f ;
byte g ;
long h ;
}
// 56byte
class C
{
long b ;
long d ;
long f ;
long h ;
byte a ;
byte c ;
byte e ;
byte g ;
}
Unity는 class에도 자동으로 적절한 메모리 레이아웃이되지 않도록 때문에 불필요한 패딩이 들어 가지 않도록 멤버 정의의 순서를 고려한다.
string s = "hoge" ;
int n = System . Text . Encoding . GetEncoding ( "UTF-8" ). GetByteCount ( s );
string s = "hoge" ;
int n = System . Text . Encoding . UTF8 . GetByteCount ( s );
GetEncoding을 호출하면 매번 클래스가 생성되기 때문에 캐시되는 UTF8을 사용한다.
for ( int i = 0 ; i < 4 ; i ++)
{
Debug . Log ( go . name );
}
name 속성에 액세스 할 때마다 GC Alloc가 발생하기 때문에 캐시한다.
등도 방문 할 때마다 문자열이 생성되어 버리므로 캐시한다.
for ( int i = 0 ; i < renderer . materials . length ; i ++)
{
}
foreach ( var m in renderer . materials )
{
}
Renderer.materials 속성에 배열을 생성 해 돌려 있기 때문에 루프에서 매번 사용하지 않도록한다.
// 80byte
foreach ( var touch in Input . touches )
{
}
// 0byte
for ( int i = 0 ; i < Input . touchCount ; i ++)
{
var touch = Input . GetTouch ( i );
}
이쪽도 배열을 생성 해 돌려 주므로 Input.GetTouch을 사용한다.
for ( int i = 0 ; i < animator . parameterCount ; i ++)
{
// animators.parameters [i] .name과 거의 같은
Debug . Log ( animator . GetParameter ( i ). name );
}
foreach ( var paramter in animator . parameters )
{
Debug . Log ( paremter . name );
}
Animator.parameters배열을 반환 API이므로 캐시한다.Animator.GetParameter치아 Animator.parameters를 내부에서 호출있을 뿐이므로 사용하지 않는다.
void GetComponentsInChildren ( List < T > results )
void GetComponentsInChildren ( List < T > results )
void GetComponentsInParent ( bool includeInactive , List < T > results )
int Physics . RaycastNonAlloc (... , RaycastHit [] results , ...)
Animator . GetCurrentAnimatorClipInfo ( int layerIndex , List < AnimatorClipInfo > clips )
몇번이나 호출하는 경우 인수 배열이나 목록을 전달하고 결과를받는 함수를 사용한다.