![[유니티 공식 유튜브] 모바일 게임 성능 최적화 - 1편](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwEsQL%2FbtrICPuqzHF%2FN3mK97diNsRslo1oawx0B1%2Fimg.png)
포트폴리오로 모바일 게임을 만들고 있어서 한번 찾아서 봤다.
유익한 정보들이 많았다.
프로파일링
첫번째로는 프로파일링의 중요성을 강조했다.
병목현상을 정리할때도 썼듯이, 어디서 병목현상이 일어나는지 알아내서 처리하는것이 중요하기 때문이다.
타겟 디바이스
타겟으로 삼고있는 디바이스로 프로파일링을 해야한다.
유니티 에디터에서 프로파일링을 한다면 에디터 처리를 하기위한 부가적인 작업들도 있기 때문에 정확한 프로파일링이 되지 않는다.
디바이스마다도 해상도도 다르고, 문제가 생길 수 있는 부분이 다르기때문에 타겟 디바이스로 프로파일링을 해야한다.
비슷한 해상도와 크기를 가진 디바이스를 타겟으로 한다면 가장 성능이 낮은 최소의 디바이스를 타겟으로 잡고 프로파일링을 하면 좋을것같다.
프로 파일러
IOS - Xcode Instruments
Android - 안드로이드 스튜디오, 안드로이드 프로파일러, 스냅드래곤 프로파일러 등등
병목현상 영상에서도 말씀 하셨는데 Xcode의 프로파일러를 극찬을 하셨다.
하드웨어와 소프트웨어의 제조사가 같기때문에 더욱 더 깊은 부분까지 프로파일링을 할 수 있어서 좋다고 한다.
온도
PC에는 거대한 쿨러가 여러개 돌아가지만, 모바일은 쿨링 시스템이라고 해봤자 히트파이프나 사진과 같이 짧은 베이퍼챔버가 전부이다.
모바일에서 열이 발생하고 열을 낮추기위해 성능을 낮추면, 서멀 스로틀링(thermal throttling)이 걸린다.
그러면 프로파일링도 부정확하게 나올 수 있기 때문에, 게임회사에서는 모바일 쿨러가 있는 경우도 있다고 한다.
프로파일링에서 봐야 하는것
우리는 FPS를 중요하게 보지만 , ms(밀리세컨드)를 잘 봐야한다고 한다.
ms: 밀리세컨드(millisecond)의 약자. 0.001초. 1000ms가 1초가 된다. 게임에서 지연 시간이나 프로그램 수행 시간을 측정할 때 초를 대신하는 시간의 단위로 활용된다.
FPS = 1000/ms
ms = 1000/FPS
서로 상관 관계를 가지기 때문에 각 작업들의 수행 시간이 얼마나 걸렸는지 보고 최적화를 진행을 해야할 항목을 알아 낼 수 있다.
메모리
모바일에서 메모리의 중요성은 더 크다.
붙어있는 하나의 램을 가지고 커널,GPU,여러 앱들이 나눠서 사용하기 때문에
핸드폰 램이 8기가가 있다고 해서 게임에 온전히 8기가를 다 사용할수는 없다.
C# 가비지 컬렉터
프로그래머들이 직접 메모리를 관리하는 (New- Delete) C++과는 다르게
C#은 C# 내부에서 가비지 컬렉터가 돌아가며 관리를 해준다.
C++의 스마트 포인터 처럼 각 메모리마다 ref count가 있고, 이 카운트가 0이되면 이 할당된 메모리를 제거하고 이빨이 빠진 부분들을 예쁘게 정리하여 재배치하는 작업을 한다(재배치, 메모리 압축)
메모리를 할당하면 그만큼 가비지 컬렉터의 호출 횟수가 늘어난다.
메모리를 대신 관리해준다고 좋아만 할게 아니라 , 위와같은 작업들이 일어나서 프레임이 여러번 튈 수 도 있는 상황을 고려하여 코드를 짤 때 잘 생각하며 짜야한다.
가비지 컬렉터를 부르는 습관들
XML/JSON 등을 이용한 문자열들의 동적파싱
동적으로 지속적인 문자열을 파싱하는 행위는 가비지 컬렉터를 자주 호출한다.
String을 사용하는 코드들
ex>
애니메이터.Getbool("스트링");
ComPareTag("스트링")
코루틴 yield return ' new '
문자열을 사용하여 무언가를 찾거나, New로 새로운것을 할당하는 코드도 주의해야한다.
애니메이터도 getbool(int id)로 대체 가능하고,
코루틴 yield return에 계속 new를 써야한다면, new로 사용하지 않고 따로 저장해두고 사용하는것이 좋다고 한다.
add, get 컴포넌트
컴포넌트를 지속적으로 붙였다 떼는것은 성능을 많이 먹는다고 한다.
또 get 을 통해 지속적으로 컴포넌트를 얻는 경우가 있는데, 이럴 경우에는 차라리 따로 변수를 선언해서 쓰는것이 좋다고 한다. (가비지 컬렉터를 발생시키며 컴포넌트를 찾기 때문에 연산이 많아짐)
다른 최적화를 위한 팁들
스크립트 실행 순서 알아두기
순서를 알아두어야 코드를 어떻게 짤지도 생각 할 수있다.
그리고 start와 update 함수는 안쓰면 지워줘야 한다.
Update를 테스트용으로 에디터상에서만 쓰고 싶으면 전처리기를 이용한다.
#if UNITY_EDITOR
void update()
{
}
#end if
Debug.log() 는 디버그라는 단어 때문에 실제 빌드하면 영향을 안미칠것같지만 아니라고 한다.
꼭 지워주자.
데이터가 필요할땐 스크립터블 오브젝트 사용하기
스크립터블 오브젝트는 직렬화가 되어있기 때문에 성능에 큰 영향을 미치지 않는다.
하지만 그냥 모노비헤이비어가 붙어있는 스크립트는 직렬화를 해주어야 하기 때문에 항목이 많으면 직렬화를 해야할 항목이 늘어나고, 성능에 영향을 준다고 한다.
물리 연산
유니티에는 그냥 오브젝트들이 있는 유니티 공간이 있고,
물리공간이 따로 있다고 한다.
그래서 이 두가지 공간을 동기화를 시켜줘야 하는데 물리연산을 하여 동기화를 하는 과정이 Fixed Update에서 일어난다고 한다.
그래서 우리는 리지드바디를 이동시킬때 fixed update에서 해줘야 했던것이며 물리API는 다 fixed update에서 처리해주면 된다고 한다.
application.targetframerate
만드는 게임이 많은 프레임을 요구하는 장르라면 안되지만
반대로 퍼즐과 같은 프레임의 수가 크게 상관이 없는 장르의 게임을 만든다면 프레임의 제한을 걸어두는것이 성능에 좋은 영향을 미친다고 한다.
고려해볼만 한 내용인 것 같다.
하이어라키를 너무 예쁘게 하지 않아도 된다.
우리가 손에 물병을 들고 팔을 이동한다면 어떻게 되는지 상상해보자.
당연히 본체인 팔이 이동이되고 팔에달리 손, 손에 들려있는 물병까지 같이 이동이된다.
하이어라키도 마찬가지다.
나도 하이어라키가 복잡하면 마음도 복잡해져서 정리하는 습관이 있는데
하이어라키상에서 한 오브젝트에 자식이 있다고 가정했을때 부모(위의 예시에선 팔)가 이동하면 밑의 자식들의 연산까지 다 이루어진다고 한다.
자식이 복잡하면 복잡할수록 악영향을 미친다.
// 1
GameObject obj = Instantiate(Object original);
obj 위치
obj 로테이션
//2
public static Object Instantiate(Object original, Vector3 position, Quaternion rotation);
Instatiate로 새로운 오브젝트를 만들때도 만들고 포지션과 로테이션을 적용시키는것이 아니라 ,
Instatiate를 쓰면서 위치,로테이션을 다 정해줄수 있으니 위 코드와 같이 사용하는것이 좋다고 한다.
포지션과 로테이션을 따로따로 적어서 2줄의 코드를 만들것이 아니라
SetPositionAndRotationd을 사용해서 1줄로 만들 수 있다.
마무리
영상에서 소개해준 내용들을 정리해봤다.
유익한 내용들이 많으니 모바일쪽에 관심 있으신 분들은 보셨으면 좋겠다.
2편이 있는데 2편까지 다 보고 정리할 예정이다.
'게임 엔진 > Unity' 카테고리의 다른 글
[유니티 공식 유튜브] IL2CPP란 무엇일까? (0) | 2022.08.09 |
---|---|
[유니티 공식 유튜브] 모바일 게임 성능 최적화 - 2편 (0) | 2022.08.07 |
유니티 알쓸유잡 - 병목현상 (0) | 2022.07.24 |
2D가 만들고싶어지는 <Lost Crypt> - 2D Sample Project (0) | 2022.07.19 |
유니티에서 비주얼 스튜디오 코드(vs Code) 사용하기 (0) | 2022.07.15 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!