유니티 + 루아 성능 최적화

연합 + 성능 최적화 루아의 주요 사항에주의를 취할 필요

치명적인 gameobj.transform.position 1. = POS를 시작합니다
 
문구의 gameobj.transform.position = POS처럼 화합, 그것은 일반적인 다른 일이지만 ulua에서, 이러한 접근의 광범위한 사용은 매우 나쁘다. 이유는 무엇입니까?
 
코드의 단 한 줄 때문에, 좀 더 직관적 위해, 우리는이 코드 줄은 키 luaapi 및 ulua 관련 주요 단계에 나열된 (ulua + 우선하는 cstolua 수출을 호출했다, 아주, 아주 많은 일을 일어난 gameobj는 게임 오브젝트이다 형, POS는) Vector3입니다 :
 
첫 번째 단계 :
GameObjectWrap.get_transform의 루아는 해당 gameobj.transform을 gameobj에서 얻을 변환 할
gameobj에 루아는 인식 아이디 C #을하게 LuaDLL.luanet_rawnetobj
ObjectTranslator.TryGetValue,이 ID로 ObjectTranslator에서 게임 오브젝트의 C #을 개체를 얻을
gameobject.transform 준비 많이, 여기에 마지막으로 정말 C #을의 구현을 gameobject.transform 수
ObjectTranslator.AddObject는 ID를 할당 변환하고, 이것은 루아에서이 표현 변환, ObjectTranslator의 미래 모습에 대한 저장 변환하는 데 사용됩니다
LuaDLL.luanet_newudata 유저 데이터의 루아에 할당 루아를 표현하는 데 사용되는 ID로 보증금은 곧 변환 반환
받는 사람 LuaDLL.lua_setmetatable는 메타 테이블 부착 UserData를, 그래서 당신이 transform.position처럼 사용할 수 있습니다
LuaDLL.lua_pushvalue 뒤에 어떻게 마무리 변환 반환
LuaDLL.lua_rawseti
LuaDLL.lua_remove
 
단계 :
TransformWrap.set_position의 루아는 POS는 transform.position로 설정하려는
루아에서 LuaDLL.luanet_rawnetobj는 인식 아이디 C #을되기 위해 변환
ObjectTranslator.TryGetValue는이 ID로 C #을 ObjectTranslator에서 오브젝트를 변환 수
플로트 3에서 Vector3의 루아를 얻을 수 LuaDLL.tolua_getfloat3은 C #을에 값을 반환
lua_getfield + lua_tonumber 3 번 XYZ의 값을 얻기 위해, 드 - 스택
lua_pop
새로운 Vector3 transform.position = (x, y, z)을 너무 많이 준비하고, 마지막 할당 transform.position = POS를 실행할
이 한 줄의 코드는, 실제로 물건 등을 많이 할 것을입니다! 의 C ++의 경우, ABC =
 
메모리 주소를 가져온 다음 일을 할당하는 것보다 더 같은 X 아무것도의 최적화 후. 그러나 여기, 자주 값, 루아에, C #을 형식 변환을 쌓아, 각 단계는 CPU 시간의 가득 차있다, 그것은 다양한 메모리 할당과 GC의 뒷면 사이에 고려하지 않았다!
 
이제 우리는 걸을려고하고, 어떤 일이 실제로 필요하지 않습니다, 그것은 생략 할 수 있습니다. 우리는 마침내 최적화에 그를 넣을 수 있습니다 :
lua_isnumber + lua_tonumber 4 회 완료
 
루아 객체의 2. ​​참조 C #을, 비용이 많이 드는
 
당신은 위의 예에서 볼 수있는, gameobj 그냥 변환에서 싶어, 그것은 C #을 객체의 매우 비싼 가격이없는 작동을위한 C에 대한 직접적인 포인터로 (사실 할 GCHandle에 의해 고정 될 수있다,하지만 어떻게 성능을 시험 등) GC 관리하여 고정의 대상이 아니므로 주류 LUA + 화합은 C에서 C # 1 물체의 ID에 의해 사전하여 해당 객체 ID로 표현된다. 때문에 사전에 기준 동시에, 또한 LUA의 경우는 C # 개체를 확인하는 쓰레기를 재활용하지 인용 하였다.
 
따라서, LUA에서 오브젝트 각 파라미터는, C # 1 ID로 다시 변환 된 오브젝트를 표시하고 사전 조회를 할; 객체 메소드 호출의 각 부재는, 먼저 오브젝트를 발견해야 할 것이다 사전 참조.
 
이 개체는 루아에서 사용 GC되지 않은 전에 있는지 확인하기 위해 다음 일은 그 또한 사전이다. 그러나 경우는 긴 목록의 위의 예에서 일할 준비가되어 객체에서 사용하지 않는 새로운 루아 것으로 확인.
 
당신이 그것으로 루아에 일시적으로 반환되는 객체 경우, 상황은 더 악화입니다! 참조 루아의 원인이 그냥 할당 된 유저 데이터 및 사전 인덱스 GC 제거, 당신은 당신이이 객체가 반복 및 유통 GC, 성능 저하의 결과로, 다시 모든 준비 작업을 수행하는 데 사용 후 다음 시간입니다.
 
gameobj.transform의 예제 때문에, 큰 함정이다. 다시 때마다 당신을 이끌 곧 루아 해방 될 것, 일시적인 수익을 변환,하지만 당신은 참조를 백업하지 않았다. 한 번 변환, 그것은 유통 및 GC를 의미 할 수있다.
 
3. LUA 및 C # (Vector3 / 쿼터니언 등) 사이의 송신 고가의 일치 값 독특한 유형
 
이후 프로그램이 주류 Vector3에게 순수 루아 코드의 다른 유형을 달성 할 수 있도록 모든이, 그 성능은 기본적으로 축소에서, C #을 통과 vector3.x 경우, 루아 느린 C #을 객체를 호출 말했듯이, Vector3은 {x는 , Y 테이블의 Z}되도록 사용 루아 빠르게.
 
# 에어콘, 그러나 이에, 그가 LUA Vector3 두 가지 전적으로 것이다 발현 후, 송신 파라미터는, 예를 들어, C 번호 Vector3 통과 루아, 전체 프로세스는 다음과 같다, 변환의 C #의 유형 및 LUA 형태에 관련한다 :
  1. C # Vector3는 X, Y, Z 세 개의 값을 얻을
  2. 루아 스택이 세 플로트를 밀어
  3. 그런 다음, 테이블, X, Y, Z 할당 테이블을 구축
  4. 이 표에 반환 값을 밀어 버린다
세 푸시 파라미터 메모리 할당 테이블을 작성하는 데 필요한 간단한 패스 파라미터는 표 3 성능 상상 될 수 있으며, 삽입된다.
 
어떻게 그것을 최적화? 우리의 테스트는 전달 함수에 직접 세 개의 플로트, 전송 Vector3보다 빠른 것을 보여준다.
예컨대 무효 SetPos (게임 오브젝트의 OBJ, Vector3pos)은 (게임 오브젝트의 OBJ 뜨는 플로트 X, Z 플로트) SetPos 무효화 효과가 특히 매우 명백한 테스트 데이터 뒤에 알 수있다.
 
4.lua 및 C #, 반환 사이를 통과하는 매개 변수, 다음과 같은 유형을 통과하지 않으려 고 :
 
심한 카테고리 : Vector3 / 사원 수 유니티 값 유형, 배열과 같은
덜 심각한 카테고리 : 부울 문자열 다양한 객체
전달 추천 : INT 이중 플로트
 
LUA 및 C # 상원 통과하지만, 비록 질량 참여하는 다양한 데이터 유형에서 (모든 루아 자체의 C 실현 후) (c)의 층, LUA, C, C 번호 의한 표현과 사실상 중간 이러한 관점, LUA 및 C # 및 메모리 할당 전략이 다르므로 세 사이의 데이터 전송은 종종 다른 종류에 따라 소비 변환 다양 (용어 파라미터 mashalling)로 변환 할 필요가있다.
 
처리의 데이터 유형에 대한 마이크로 소프트의 공식 문서에 따르면, 저를 C 및 C # 상호 작용 성능 소비를 포함, 덜 심각한 수준의 부울 문자열 유형에 대해 얘기하자, C #을 부울 및 문자열이 비에 속하는 Blittable 형식 및 비 Blittable 유형을 정의 -Blittable 유형, 그들은 C에 존재 및 C # 그것을 필요로 할 때, 성능이 저하 될뿐만 아니라, 관리되는 힙 메모리에 문자열을 복사 (문자열 메모리 할당을 고려 C # 형식 변환에 C에서 통과 의미, 동일하지 나타내는 의미 등) UTF8과 UTF16 시스템 변환.
 
https://msdn.microsoft.com/zh-cn/library/ms998551.aspx를 참조 할 수 있습니다, 여기에 C와 C #의 최적화 가이드 라인의 상호 작용의 성능에 대한 자세한 내용입니다.
그리고 인해 C #을 심각한 종류, 개체에 해당하는 개체의 기본적 ulua 프로그램 등의 시도 루아 병목 현상.
소비의 Vector3 해당하는 유형은 이미 언급되었다.
어레이의 LUA 테이블 만 표현 될 수 있기 때문에, 어레이는 더욱 심각하고, luatable 기초 만 배열 C #을 변환 복사되도록 객체 / 문자열 등 관련된 경우 완전히 상이한는 C #은, 직접적인 관계가없는 그것은 하나 하나를 변환하는 것입니다.
 
기능의 수는, 매개 변수가 자주 호출 제어 할 수
 
이 C # 1 패스 파라미터 루아 pushint / checkint 또는 C인지, 파라미터 변환 중요한 소비하며, 하나 개의 파라미터에 의해 수행되고, 따라서, LUA 호 C # 1 성능 파라미터 유형과 관련된뿐만 아니라 매개 변수 이외에 좋은 관계의 수입니다. 자주 호출하는 경우 일반적으로, 함수는 다스 인수보다 더 자주 더 자주하지 최대 4 개의 매개 변수,라고, 당신은 매우 중요한 성능 저하를 볼 수 있습니다, 하나는 전화를 수백 번 호출 할 수 있습니다, 당신은 10ms를 볼 수 있습니다 레벨 시간.
 
제 우선 정적 내보내기 기능을 사용 내보내기 방법의 부재의 사용을 줄이기
 
앞서 언급, 액세스 방법 또는 멤버 변수에 대한 구성원 개체는, 우리는 많은 소비, 루아 유저 데이터 및 C # 객체 참조를 찾거나 메타 테이블을 찾을 필요가있다. 직접 수출 정적 기능은 이러한 소비를 줄일 수 있습니다.
 
像 = POS obj.transform.position.
우리의 권장되는 방법은 정적 내보내기 기능, 유사한로 작성
클래스 LuaUtil { 
  정적 무효 SetPos (게임 오브젝트의 OBJ 플로트 X, Y 플로트, 플로트 Z) = {obj.transform.position 새로운 Vector3 (X, Y, Z); } 
}
 
자주에 대한 필요성을 제거하여 수익을 변환뿐만 아니라 종종 일시적으로 반환 루아의 원인이 변환을 피할 수 있기 때문에 그런 LuaUtil.SetPos (OBJ, pos.x, pos.y, pos.z)에 루아,이 성능이 더 많이 될 것입니다 GC가.
 
메모리 누수의 일반적인 원인 인 객체가 발생할 루아 유지 퍼런 C C # 1 # 1 오브젝트가 해제 될 수없는 7 참고
 
앞서 언급 한 바와 같이, C #을 다시 LUA 반대만큼 루아 유저 데이터가 복구되지는 C # 1 오브젝트의이 사전에 대한 참조를 보유한다 유저 데이터의 LUA 및 C #, 회합하여 객체 사전이며, 원인은 회수 할 수 없다.
 
당신이 파괴하더라도 그 안에서 루아 참조, 또한 그들은 여전히 ​​모노 더미에 남아있는 것을 발견하면 가장 일반적인, 게임 오브젝트와 구성 요소입니다.
 
사전은 C #을 수있는 유일한 협회 루아가 있기 때문에, 그래서이 문제의 인식은이 사전에 대해 횡단하는 찾을 매우 쉽게, 어려운 일이 아니다. 이 카테고리 사전에 ulua ObjectTranslator, ObjectCache에서 slua 클래스
 
8. 오브젝트 C #을 직접 참조하지 않고, 루아 만 자신의 관리 ID를 사용하는 것을 고려
 
루아는 C #을에 대한 참조를 피하려고
 
다양한 성능은 한 가지 방법은 개체 ID 할당 내보내기 기능은 인수로 전달 더 이상 관련이 C #을 개체가없는 반면, 인덱스 오브젝트에 자신을 가지고하는 것입니다 발행하지만, 패스 INT.
 
이것은 몇 가지 장점을 제공합니다 :
  1. 기능은 더 나은 성능을 호출;
  2. 명시 적으로 객체의 수명주기를 관리, 잘못 객체의 원인이됩니다 루아에서 이러한 개체를 참조하는 경우 ulua가 자동으로 해제 할 수 없습니다 이러한 개체 참조를 관리 피하기 메모리 누수 있도록
  3. C #을 객체는 루아에 대한 참조가없는 경우, 쉽게 바로 GC, 및 객체 참조하는 ObjectTranslator 삭제됩니다, 루아에 돌려 보냈다. 이 자기 참조 노사 관계는 GC 동작을하지 않았을 및 유통 행위가 자주 발생합니다.
예를 들어, 상기 LuaUtil.SetPos (게임 오브젝트의 OBJ 플로트 X, Y 플로트, floatz)는 상기 (OBJID 플로트 X, 뜨는, floatz를 INT) LuaUtil.SetPos에 최적화 될 수있다. 그리고 우리는 가능하면, 오히려 사전을 기록 할 배열을 사용하는 것보다, 다음 빨리 효율성을 검색가있을 것입니다, 내 자신의 코드에 게임 오브젝트와 OBJID의 대응을 기록합니다. 그래서 아래로 더 시간 루아 호출 C #을 저장 및 개체 관리를보다 효율적으로 될 것입니다.
 
9. 키워드의 합리적인 사용은 복잡한 반환 값을 반환
 
반환 다양한 형태의 대중 참여와 C #을 비슷한 일 루아뿐만 아니라 소비의 다양한 있습니다.
 
예를 들어 Vector3 GetPos (게임 오브젝트의 OBJ)는 (floatz 밖으로 유동 예에서, 플로트 (X)의 밖으로 게임 오브젝트 OBJ) 보이드 GetPos 같이 쓸 수있다
 
생성 된 코드에 표면 파라미터의 수를 증가하지만 아웃 따른로부터 (로모 Ulua 따라) 도출한다 : LuaDLL.tolua_getfloat3 (함유 get_field + tonumber 3 회) ISNUMBER tonumber + 3 번이되고
 
get_field에 너무 너무 더 나은 성능을해야합니다 할 본질적으로 ISNUMBER 액세스 스택에 비해 확실히 느린 테이블 조회입니다.
 
측정
 
글쎄, 난 여기에 시간의 첫 번째 부분이 있기 때문에 너무 많은 데이터의 관점을하지 않는 것은, 순수한 언어 자체가, 우리가 직접 gameobj.transform.position의 예를 사용하지 않는 볼보다 현실적인 소비하기 위해 너무 불분명했다 폐기물의 내부 단결이다.
 
우리는 GameObject2 및 Transform2의 단순화 된 버전을 다시 썼다.
클래스 Transform2 { 
  공개 Vector3 위치 = 새로운 Vector3 (); 
} 
클래스는 {GameObject2 
   공개 Transform2는 () = 새로운 Transform2 변환; 
}
 
그런 다음 우리는 설정 위치 변환을 호출하는 여러 가지 방법을 사용하여
方式 1 gameobject.transform.position Vector3.New = (1,2,3)
모드 2 : 게임 오브젝트 : SetPos (Vector3.New (1,2,3))
모드 3 : 게임 오브젝트 : SetPos2 (1,2,3)
方式 4 GOUtil.SetPos (게임 오브젝트, Vector3.New (1,2,3))
方式 5 GOUtil.SetPos2 (gameobjectid, Vector3.New (1,2,3))
방법 6 : GOUtil.SetPos3 (gameobjectid, 1,2,3)
 
1,000,000, 각각 다음과 같은 결과가 (테스트 환경은 윈도우 버전이며, CPU가 i7-4770, JIT 모드 해제의 luajit입니다 luajit 아키텍처, il2cpp 간섭 및 기타 요인이 다르기 때문이 아니라 전화에있을 것입니다,이 다음 일 우리는 더 것 ) 정교한 :
 
모드 1 : 903ms
모드 2 : 539ms
모드 3 : 343ms
모드 4 : 559ms
모드 5 : 470ms
방법 6 : 304ms
 
우리는 각각의 최적화, 크게, 특히 모두 제거 증가를 볼 수 있습니다. 변환 및 Vector3 변환 업그레이드가 크다 얻을, 우리가 해외 수출의 방식을 변경, 높은 비용을 지불 할 필요가 없다, 시간의 66 퍼센트 절약 할 수있을 것입니다.
 
사실 우리는 더 이상 갈 수없는 이유는 무엇입니까? 또한! 방법 6을 바탕으로, 우리는 단지 200 밀리 할 수있다!
 
여기에 비밀, 다음 luajit 통합은 우리가 더 설명한다. 일반적으로 우리가하는 방식의 레벨이 6이 충분한 좋습니다.
 
이건 그냥 가장 간단한 경우 중 하나입니다, 많은 일반적으로 사용되는 수출의 종류가있다, 우리는 자신의 용도에 따라 최적화 할 필요가있다 (예를 들어 GetComponentsInChildren이 성능 구덩이, 또는 매개 변수의 기능은 더 다스의 경우보다 통과 된)이 있습니다 우리가 분석 뒤에 제공하는 통합 솔루션의 루아 성능 원리는, 당신은 쉽게 할 방법을 고려해야한다.
 
다음은 유니티 루아 + 성능 최적화, luajit 통합 성능 구덩이의 두 번째 부분을 작성합니다
 
코드의 첫 번째 부분에 비해이 아마 소비의 문제를 알고 수출 실적을 볼 수있을 것이다, luajit 통합 문제는 훨씬 더 복잡 불분명.
 
C # 코드는 테스트에 부착 :
Public 클래스 Transform2 
{ 
    공개 Vector3 위치 = 새로운 Vector3 (); 
} 
공용 클래스 GameObject2는 
{ 
    공개 Transform2는 () = 새로운 Transform2 변환; 
    공공 무효 SetPos (Vector3 볼때) 
    { 
        transform.position = POS; 
    } 
    공개 무효 SetPos2 (플로트 X는 Z 플로트, 플로트 Y) 
    { 
        transform.position.x = X; 
        transform.position.y = Y; 
        transform.position.z = Z; 
    } 
} 
공용 클래스 GOUtil 
{ 
    개인 정적 목록 <GameObject2> mObjs = 새로운 목록 <GameObject2> (); 
    공공 정적 GameObject2 GetByID (INT 아이디) 
    {
        경우 (mObjs.Count == 0) 
        { 
            대해 INT (I = 0; I <1000; 내가 ++) 
            { 
                mObjs.Add (새 GameObject2 ()); 
            } 
        } 
        mObjs [ID]를 복귀; 
    } 
    공공 정적 무효 SetPos (GameObject2는 Vector3 볼때 이동) 
    { 
        go.transform.position = POS 단계; 
    } 
    공공 정적 무효 SetPos2 (INT 자료, Vector3 POS) 
    { 
        mObjs [ID] = .transform.position POS; 
    } 
    공공 정적 무효 SetPos3 (INT 자료, X 플로트, 플로트 Y, Z 플로트) 
    { 
        var에 t = mObjs [ID] .transform; 
        t.position.x = X;
        t.position.y = Y;
        t.position.z = Z; 
    } 
}
올린 사람 : HTTPS : //blog.csdn.net/haihsl123456789/article/details/54017522/

추천

출처www.cnblogs.com/scoregao/p/10984190.html