TA/Unity2013. 9. 9. 17:46

출처 : http://egohim.blog.me/70170987774

 

 

 

참고 : Practical Guide to Optimization for Mobiles - Future & High End Devices

참고 : Practical Guide to Optimization for Mobiles - Graphics Methods

참고 : Practical Guide to Optimization for Mobiles - Scripting and Gameplay Methods

참고 : Practical Guide to Optimization for Mobiles - Rendering Optimizations

참고 : Practical Guide to Optimization for Mobiles - Optimizing Scripts

 

// Practical Guide to Optimization for Mobiles 

참고 : http://docs.unity3d.com/Documentation/Manual/iphone-PracticalScriptingOptimizations.html

1.Class vs Struct

Classes are objects and behave as references. If Foo is a class and

 Foo foo = new Foo();

 MyFunction(foo); 

then MyFunction will receive a reference to the original Foo object 

that was allocated on the heap. 

Any changes to foo inside MyFunction will be visible anywhere foo is referenced.

-C#에서 클래스는 함수 인자로 넘길 대 레퍼런스화 되서 작동 한다만약 Foo클래스가 Foo foo = new Foo();로 선언되었다면

  MyFunction(foo);에서 MyFunction은 힙 메모리 영역에 선언된 Foo 오브젝트의 레퍼런스로 받게 된다.

  만약 foo MyFunction안에서 어떤 변화가 있다면 foo의 참조를 받는 그 어디에서라도 그것이 적용되게 된다.

 

If Foo is a struct and

 Foo foo = new Foo();

 MyFunction(foo); 

then MyFunction will receive a copy of foo. 

foo is never allocated on the heap and never garbage collected. 

If MyFunction modifies it's copy of foo, the other foo is unaffected.

-만약 Foo가 구조체(Struct)로 선언되어있다면 Foo foo = new Foo(); MyFunction(foo);로 선언된 MyFunction(foo); 에서

  MyFunction함수는 foo가 복사 되어 받게 된다.

  foo는 절대 힙메모리 영역에 할당되지 않으며또한 절대 가비지 콜렉트되지 않는다.

  만약 MyFunction에서 foo가 넘어가면 foo가 복사되기 때문에 함수내에서 변경해도 다른 참조된 foo에 영향을 주지 않고,

  스코프를 벗어나면 자동 소멸 된다.

 

 

// Understanding Automatic Memory Management

참고 : http://docs.unity3d.com/Documentation/Manual/UnderstandingAutomaticMemoryManagement.html

 

2. String 배열의 메모리 단편화 문제 

function ConcatExample(intArray: int[]) {

 var line = intArray[0].ToString();

 for (i = 1; i < intArray.Length; i++) {

  line += ", " + intArray[i].ToString();

 }

 return line;

}

 

-> String Builder 사용을 추천.

StringBuilder sb = new StringBuilder();

ShowSBInfo(sb);

sb.Append("This is a sentence.");

ShowSBInfo(sb);

for (int ctr = 0; ctr <= 10; ctr++) {

 sb.Append("This is an additional sentence.");

 ShowSBInfo(sb);

 

3. 가변 시에만 메모리 할당 처리

 var scoreBoard: GUIText;

 var score: int;

 

 function Update() {

  var scoreText: String = "Score: " + score.ToString();

  scoreBoard.text = scoreText;

 }

...will allocate new strings each time Update is called and generate a constant trickle of new garbage. Most of that can

be saved by updating the text only when the score changes:-
매 업데이트 할때 마다 새로운 String 생성으로 가비지가 생성되는 비효율적인 문제로 텍스트를 가변 상황에만 String할당.

 var scoreBoard: GUIText;

 var scoreText: String;

 var score: int;

 var oldScore: int;

 

 function Update() {

  if (score != oldScore) {

   scoreText = "Score: " + score.ToString();

   scoreBoard.text = scoreText;

   oldScore = score;

  }

 }

 

 

4. 배열 생성 반환 함수의 잠재적인 문제
potential problem occurs when a function returns an array value:-

 function RandomList(numElements: int) {

  var result = new float[numElements];

  for (i = 0; i < numElements; i++) {

   result[i] = Random.value;

  }

 

  return result;

 }

This type of function is very elegant and convenient when creating a new array filled with values. However, if it is called repeatedly
then fresh memory will be allocated each time. Since arrays can be very large, the free heap space could get used up rapidly,
resulting in frequent garbage collections. One way to avoid this problem is to make use of the fact that an array is a reference type. An array passed into a function as a parameter can be modified within that function and the results will remain after the function returns. A function like the one above can often be replaced with something like:-

 function RandomList(arrayToFill: float[]) {

  for (i = 0; i < arrayToFill.Length; i++) {

   arrayToFill[i] = Random.value;

  }

 }

This simply replaces the existing contents of the array with new values. Although this requires the initial allocation of the array to be done in the calling code (which looks slightly inelegant), the function will not generate any new garbage when it is called.

4. Garbage Collection 
호출 전략 
4-1. Small heap with fast and frequent garbage collection (빠르고 적은 힙 그리고 빈번한 가비지 콜렉션 방식)
This strategy is often best for games that have long periods of gameplay where a smooth framerate is the main concern. A game like this will typically allocate small blocks frequently but these blocks will be in use only briefly. The typical heap size when using this strategy on iOS is about 200KB and garbage collection will take about 5ms on an iPhone 3G. If the heap increases to 1MB, 

the collection will take about 7ms. It can therefore be advantageous sometimes to request a garbage collection at a regular frame interval. This will generally make collections happen more often than strictly necessary but they will be processed quickly and with minimal effect on gameplay:-
- iOS iPhone 3G 
에서 200KB garbage collection하는 데 5ms 가 걸리고,
                                 1MB
   garbage collection하는데 7ms 가 걸린다. - 

 if (Time.frameCount % 30 == 0)

 {

    System.GC.Collect();

 }

 

However, you should use this technique with caution and check the profiler statistics to make sure that it is really reducing collection time for your game.
그러나 위 방식을 체택 할 경우 프로파일러 통계로 명확하게 체크 할 것을 요한다.

4-1. Large heap with slow but infrequent garbage collection (큰 힙과 느리지만빈번하지 않은 가비지 콜렉션 방식)

This strategy works best for games where allocations (and therefore collections) are relatively infrequent and can be handled during pauses in gameplay. It is useful for the heap to be as large as possible without being so large as to get your app killed by the OS due to low system memory. However, the Mono runtime avoids expanding the heap automatically if at all possible. You can expand the heap manually by preallocating some placeholder space during startup (ie, you instantiate a "useless" object that is allocated purely for its effect on the memory manager):-
-
최고의 게임에서 빈번하지 않게 가비지 콜렉트를 호출하는 전략은 게임 플레이가 멈춘 동안에 다루는 것이다. ... 

 function Start() {

  var tmp = new System.Object[1024];

 

  // make allocations in smaller blocks to avoid them to be treated in a special way, which is designed for large blocks

         for (var i : int = 0; i < 1024; i++)

   tmp[i] = new byte[1024];

 

  // release reference

         tmp = null;

 }

 

A sufficiently large heap should not get completely filled up between those pauses in gameplay that would accommodate a collection. When such a pause occurs, you can request a collection explicitly:-
System.GC.Collect();
Again, you should take care when using this strategy and pay attention to the profiler statistics rather than just assuming it is having the desired effect.

// Practical Guide to Optimization for Mobiles - Optimizing Scripts
http://docs.unity3d.com/Documentation/Manual/iphone-PracticalScriptingOptimizations.html#Object%20Pooling
 

// Optimization for Mobiles - Scripting and Gameplay Methods

http://docs.unity3d.com/Documentation/Manual/iphone-OptimizedScriptingMethods.html

 

 

// 마소 C# 메모리 최적화 글 -good

http://www.imaso.co.kr/?doc=bbs/gnuboard.php&bo_table=article&wr_id=40743

 

// 마소 유니티 메모리 최적화 글

http://www.imaso.co.kr/?doc=bbs/gnuboard.php&bo_table=article&wr_id=41284

 

이하 인용....

유니티 스크립트 중에 최적화란 관점에서는 중요한 두 가지 함수가 존재한다명시적으로 GC를 호출하는 System.gc.collect와 

현재 사용하지 않는 리소스를 해제하는 Resources.Unload UnusedAssets란 함수다보통 scene이 바뀌거나 메모리를 

한번 비우고 가고 싶을 때 호출하게 되는데 두 함수만 열심히 호출한다고 해서 모든 문제가 해결되는 것은 아니다

 

...

개발하던 게임에서는 GUI를 위한 여러 텍스처들이 사용되고 있었는데 몇 개의 텍스처가 NPOT(non power of two)로 제작돼 있었다

OpenGL ES2를 지원하는 최근의 디바이스들은 NPOT 텍스처를 제한적으로 지원하고 있으나 유니티는 호환성을 위해 

NPOT 텍스처의 경우 내부적으로 별도의 처리를 하는 것으로 보인다

프로파일링 결과 POT 대비 2배의 메모리를 사용하는 것으로 생각되는데비디오 메모리를 많이 사용하는 게임에서는 특히 

유념해야 할 부분이다.

 

Posted by 프리랜서 디자이너