성능 개선

*이 콘텐츠는 AI(베타)를 사용해 번역되었으며, 오류가 있을 수 있습니다. 이 페이지를 영어로 보려면 여기를 클릭하세요.

이 페이지에서는 일반적인 성능 문제와 이를 완화하기 위한 모범 사례를 설명합니다

스크립트 계산

Luau 코드의 비용이 많이 드는 작업은 처리하는 데 더 오래 걸리고 따라서 프레임 속도에 영향을 줄 수 있습니다.병렬로 실행되지 않는 한 Luau 코드는 스레드를 반환하는 함수를 만날 때까지 동기적으로 실행되며 주 스레드를 차단합니다.

공통 문제

  • 테이블 구조에 대한 집중적인 작업 - 직렬화, 디직렬화 및 깊은 복제와 같은 복잡한 작업은 특히 큰 테이블 구조에서 높은 성능 비용을 발생시킵니다.이 작업이 재귀적이거나 매우 큰 데이터 구조를 반복하는 경우에 특히 그렇습니다.

  • 높은 주파수 이벤트 - 주파수를 제한하지 않고 비용이 많이 드는 작업을 프레임 기반 이벤트의 RunService에 결속하여 이러한 작업이 모든 프레임에서 반복되므로 계산 시간이 불필요하게 증가합니다.이 이벤트에는 다음이 포함됩니다:

해결책

  • RunService 이벤트에서 코드를 적게 호출하여 높은 빈도의 호출이 필수인 경우(예: 카메라 업데이트)에만 사용을 제한합니다.다른 이벤트에서 대부분의 다른 코드를 실행하거나 루프에서 덜 자주 실행할 수 있습니다.
  • task.wait()를 사용하여 큰 또는 비용이 많이 드는 작업을 분할하여 작업을 여러 프레임에 분산합니다.
  • 불필요하게 비싼 작업을 식별하고 최적화하고 데이터 모델에 액세스할 필요가 없는 계산적으로 비싼 작업에 대해 멀티스레딩을 사용합니다.
  • 특정 서버 사이드 스크립트는 네이티브 코드 생성을 활용할 수 있으며, 스크립트를 바이트코드가 아닌 기계 코드로 컴파일하는 간단한 플래그입니다.

마이크로프로파일러 스코프

영역관련 계산
운영 서비스.PreRenderPreRender 이벤트에서 코드 실행
실행 서비스.PreSimulation스텝 이벤트에서 코드 실행
실행 서비스.PostSimulation하트비트 이벤트에서 코드 실행하기
운영 서비스.하트비트하트비트 이벤트에서 코드 실행하기

MicroProfiler를 사용하여 스크립트를 디버깅하는 자세한 정보는 debug 라이브러리를 참조하십시오, 특정 코드를 태그하고 특정성을 향상시키기 위한 함수를 포함합니다. 예를 들어 debug.profilebegindebug.profileend .스크립트에 의해 호출되는 많은 Roblox API 메서드도 유용한 신호를 제공할 수 있는 자체 연결된 마이크로프로필러 태그가 있습니다.

스크립트 메모리 사용量

메모리 누수는 가비지 수집기가 더 이상 사용되지 않을 때 메모리를 소비하는 스크립트를 작성하면 발생할 수 있습니다. Memory leaks can occur when you write scripts that consume memory that the garbage collector can't properly release when its no longer in use.누출은 특히 서버에서 널리 퍼져 있으며, 클라이언트 세션은 훨씬 짧기 때문입니다. 클라이언트 세션은 며칠 동안 연속으로 온라인일 수 있지만, 누출은 몇 주 동안 계속 온라인일 수 있습니다.

개발자 콘솔의 다음 메모리 값 은 추가 조사가 필요한 문제를 나타낼 수 있습니다:

  • LuaHeap - 높거나 증가하는 소비는 메모리 누수를 암시합니다.
  • 인스턴스 수 - 일관되게 증가하는 인스턴스 수는 코드에서 일부 인스턴스에 대한 참조가 수집되지 않는다는 것을 암시합니다.
  • PlaceScriptMemory - 메모리 사용 분석에 따른 스크립트를 제공합니다.

공통 문제

  • 연결된 연결 유지 - 엔진은 연결된 콜백에 연결된 인스턴스와 참조된 모든 값에 대해 결코 가비지 수집을 수행하지 않습니다.따라서 연결된 인스턴스, 연결된 함수 및 참조된 값 내의 이벤트와 코드의 활성 연결은 이벤트가 발생한 후에도 메모리 가비지 수집기의 범위를 벗어납니다.

    인스턴스에 속한 이벤트가 연결이 끊어지더라도, 일반적인 실수는 이것이 Player 개체에 적용된다고 가정하는 것입니다.사용자가 경험을 떠났을 때 엔진은 대표자 개체와 캐릭터 모델의 특성 모델에 대한 연결을 자동으로 파괴하지 않으므로 스크립트에서 연결을 끊지 않으면 캐릭터 모델의 개체와 특성 모델(예: )에 여전히 메모리가 소모됩니다.이로 인해 수백 명의 사용자가 경험에 참여하고 떠날 때 서버에서 매우 심각한 메모리 누출이 발생할 수 있습니다.

  • 테이블 - 더 이상 필요하지 않을 때 테이블에 개체를 삽입하지만 제거하지 않으면 특히 사용자 데이터를 추적하는 테이블의 불필요한 메모리 소비가 발생합니다.예를 들어 다음 코드 샘플은 사용자가 참여할 때마다 사용자 정보를 추가하는 테이블을 생성합니다:

    예제

    local playerInfo = {}
    Players.PlayerAdded:Connect(function(player)
    playerInfo[player] = {} -- 일부 정보
    end)

    이러한 항목이 더 이상 필요하지 않을 때 제거하지 않으면 테이블의 크기가 계속 증가하고 더 많은 사용자가 세션에 참여함에 따라 메모리가 더 많이 소비됩니다이 테이블을 반복하는 모든 코드는 테이블 크기가 증가함에 따라 계산 비용이 더 많이 증가합니다.

해결책

메모리 누수를 방지하기 위해 사용된 모든 값을 정리하려면:

  • 모든 연결 끊기 - 코드 베이스를 통해 각 연결이 다음 경로 중 하나를 통해 정리되도록 확인합니다.

    • Disconnect() 함수를 사용하여 수동으로 연결 해제 중.
    • Destroy() 함수로 이벤트가 속한 인스턴스를 파괴합니다.
    • 연결이 거슬러 올라가는 스크립트 개체를 파괴합니다.
  • 플레이어 개체와 캐릭터를 제거하고 나간 후 - 사용자가 나간 후에도 연결이 유지되지 않도록 코드를 구현하십시오, 다음 예제와 같이:

    예제

    Players.PlayerAdded:Connect(function(player)
    player.CharacterRemoving:Connect(function(character)
    task.defer(character.Destroy, character)
    end)
    end)
    Players.PlayerRemoving:Connect(function(player)
    task.defer(player.Destroy, player)
    end)

물리학 계산

과도한 물리 시뮬레이션은 서버와 클라이언트 모두에서 프레임당 계산 시간 증가의 주요 원인이 될 수 있습니다.

공통 문제

  • 과도한 물리 시간 단계 빈도 - 기본적으로 스텝 동작은 물리 스텝이 60Hz, 120Hz 또는 240Hz, 물리 메커니즘의 복잡성에 따라 달라지는 적응 모드에 있습니다.

    물리학의 정확도가 향상된 고정 모드도 사용할 수 있으며, 모든 물리학 어셈블리가 240Hz(프레임당 4번)로 스텝하도록 강제합니다이로 인해 각 프레임에서 훨씬 더 많은 계산이 수행됩니다.

  • 시뮬레이션된 개체의 복잡도 과다 - 시뮬레이션되는 3D 어셈블리가 많을수록 물리 계산이 각 프레임에 걸리는 시간이 길어집니다종종 경험에는 필요하지 않거나 필요한 것보다 더 많은 제약 조건과 관절이 있는 메커니즘이 시뮬레이션되는 경우가 많습니다.

  • 과도하게 정확한 충돌 감지 - 메쉬 부품에는 충돌을 감지하기 위한 CollisionFidelity 속성이 있으며, 성능 영향 수준이 다른 다양한 모드를 감지하는 데 사용됩니다.메쉬 부품의 정밀 충돌 감지 모드는 가장 비싼 성능 비용을 가지며 엔진이 계산하는 데 더 오래 걸립니다.

해결책

  • 시뮬레이션이 필요하지 않은 고정 부품 - 정적 NPC와 같이 물리학에 의해 구동되지 않아야 하는 모든 부품을 고정합니다.

  • 적응형 물리 스텝 사용 - 적응형 스텝은 물리 메커니즘에 대한 물리 계산 속도를 동적으로 조정하여 일부 경우에 물리 업데이트를 덜 자주 수행할 수 있습니다.

  • 메커니즘 복잡성 줄이기 * 가능하면 조립에서 물리적 제약 조건이나 조인트의 수를 최소화하십시오.

    • 제한이나 무충돌 제약 조건을 적용하여 래그돌 팔에 자체 충돌이 발생하지 않도록 함으로써 메커니즘 내의 자체 충돌 양을 줄이십시오. Reduce the amount of self-collision within a mechanism, such as by applying limits or no-collision constraints to ragdoll limbs to prevent them from colliding with each other.
  • 메쉬의 정밀한 충돌 신뢰도 사용 줄이기 * 사용자가 차이를 거의 알지 못하는 작은 또는 상호 작용할 수 없는 개체에서는 상자 충실도를 사용하십시오.

    • 소형 중형 크기 개체의 경우 모양에 따라 상자 또는 선체 정밀도를 사용합니다.

    • 대형 및 매우 복잡한 개체의 경우 가능하면 투명한 부품을 사용하여 사용자 지정 충돌을 구축하십시오.

    • 충돌이 필요하지 않은 개체의 경우 충돌을 비활성화하고 상자 또는 선체 정확도를 사용하여 충돌 지오메트리가 여전히 메모리에 저장되기 때문에 충돌 정확도를 사용합니다.

    • 3D 뷰포트의 오른쪽 상단에 있는 시각화 옵션 위젯에서 충돌 정확도를 토글하여 Studio에서 디버그 목적으로 충돌 기하학을 렌더링할 수 있습니다.

      또한, 모든 메시 부품의 정확한 품질과 쉽게 선택할 수 있도록 모든 메시 부품의 수를 표시하는 CollisionFidelity = Precise필터를 적용할 수도 있습니다.

    • 정밀도와 성능 요구 사이에서 균형을 맞추는 충돌 정확도 옵션을 선택하는 방법에 대한 자세한 설명은 물리 및 렌더링 매개 변수 설정을 참조하십시오.

마이크로프로파일러 스코프

영역관련 계산
물리학 단계별전체 물리학 계산
월드스텝각 프레임에서 수행된 불연속 물리 단계

물리 메모리 사용량

물리 이동과 충돌 감지는 메모리를 소비합니다.메쉬 부품에는 CollisionFidelity 속성이 있으며, 메쉬의 충돌 경계를 평가하는 데 사용되는 접근법을 결정합니다.

공통 문제

기본 및 정밀한 충돌 감지 모드는 낮은 정확도의 충돌 모양을 가진 다른 두 모드보다 훨씬 더 많은 메모리를 사용합니다. 물리 부품 아래에서 메모리 사용량이 높은 경우 경험의 개체의 충돌 정확도를 줄이는 방법을 조사해야 할 수 있습니다.

대응 방법

충돌 정확도에 사용되는 메모리를 줄이려면:

  • 충돌이 필요하지 않은 부품의 경우, BasePart.CanCollide , BasePart.CanTouchBasePart.CanQueryfalse 으로 설정하여 충돌을 비활성화합니다.
  • CollisionFidelity 설정을 사용하여 충돌의 정확도를 줄입니다.Box 는 가장 낮은 메모리 오버헤드를 가지며, DefaultPrecise 는 일반적으로 더 비싸다.
    • 일반적으로 작은 고정 부품의 충돌 정확도를 Box로 설정하는 것이 안전합니다.
    • 매우 복잡한 대형 메쉬의 경우 상자 충돌 정확도를 가진 더 작은 개체로 자체 충돌 메쉬를 빌드하는 것이 좋습니다.

인간형

Humanoid 는 플레이어와 플레이어가 아닌 캐릭터(NPC)에게 다양한 기능을 제공하는 클래스입니다.강력하지만, Humanoid 는 상당한 계산 비용이 듭니다.

공통 문제

  • NPC에서 모든 HumanoidStateTypes를 활성화한 채로 떠나기 - 특정 HumanoidStateTypes 활성화를 떠나는 데 성능 비용이 발생합니다.NPC에 필요하지 않은 것을 비활성화합니다.예를 들어, NPC가 사다리를 오르지 않는 한, Climbing 상태를 비활성화하는 것이 안전합니다.
  • 인간형 모델을 자주 생성, 수정 및 재생하여 모델 재사용 * 특히 이러한 모델이 분층 의류 를 사용하는 경우 엔진이 처리하기 위해 집중적으로 작업해야 합니다.이는 아바타가 자주 재생성되는 경험에서 특히 문제가 될 수 있습니다.
    • 마이크로프로파일러 에서는 긴 업데이트가 취소된 빠른 클러스터 태그(4ms 이상)가 종종 아바타 인스턴스화/수정이 과도한 무효화를 트리거하고 있음을 신호로 합니다.
  • 필요하지 않은 경우 인간형을 사용하는 것 - 일반적으로 이동하지 않는 정적 NPC는 Humanoid 클래스에 필요가 없습니다.
  • 서버에서 대규모 NPC에 애니메이션 재생 - 서버에서 실행되는 NPC 애니메이션은 서버에서 시뮬레이션되고 클라이언트에 복제되어야 합니다.이는 불필요한 오버헤드가 될 수 있습니다.

해결책

  • 클라이언트에서 NPC 애니메이션 재생 - 많은 NPC가 있는 경험에서는 NPC의 Animator를 클라이언트에 생성하고 애니메이션을 로컬로 실행하는 것을 고려하십시오.이렇게 하면 서버의 부하가 줄어들고 불필요한 복제가 필요하지 않습니다.또한 추가 최적화를 가능하게 합니다(예: 캐릭터에 가까운 NPC에 대해서만 애니메이션을 재생하는 것과 같음).
  • 성능 친화적인 대안을 사용하여 Humanoids를 사용하지 마십시오 - NPC 모델에 반드시 인간형 개체가 포함되어 있을 필요는 없습니다
    • 정적 NPC의 경우 간단한 AnimationController 를 사용하십시오, 이들은 이동할 필요가 없고 단지 애니메이션을 재생할 필요가 있기 때문입니다.
    • NPC를 이동하려면 NPC의 복잡성에 따라 자체 이동 컨트롤러를 구현하고 애니메이션에는 AnimationController를 사용하는 것이 좋습니다.
  • 사용되지 않은 휴머노이드 상태 비활성화 - Humanoid:SetStateEnabled()를 사용하여 각 휴머노이드에 필요한 상태만 활성화하십시오.
  • 자주 재생성되는 NPC 풀 모델 - NPC를 완전히 파괴하는 대신, NPC를 비활성 NPC 풀로 보내십시오.이런 식으로, 새로운 NPC가 재생성되어야 할 때 풀에서 NPC 중 하나를 다시 활성화할 수 있습니다.이 프로세스는 풀링이라고 하며, 문자를 인스턴스화해야 하는 횟수를 최소화합니다.
  • 사용자가 근처에 있을 때만 NPC 생성 - 사용자가 범위에 없을 때 NPC를 생성하지 않고, 사용자가 범위를 떠날 때 제거합니다.
  • 인스턴스화된 후에는 아바타 계층에 변경을 주지 않도록 하십시오 - 아바타 계층에 대한 특정 수정은 성능에 중요한 영향을 미칩니다.다음 최적화가 사용 가능합니다:
    • 사용자 지정 절차 애니메이션의 경우, JointInstance.C0JointInstance.C1 속성을 업데이트하지 마십시오. 대신 Motor6D.Transform 속성을 업데이트하십시오.
    • 아바타에 모든 BasePart 개체를 연결해야 하는 경우, 아바타의 계층 밖에서 그렇게 하십시오. Model .

마이크로프로파일러 스코프

영역관련 계산
스텝휴머노이트휴머노이드 제어 및 물리학
스텝 애니메이션휴머노이드 및 애니메이터 애니마션
업데이트된 무효한 빠른 클러스터아바타 생성 또는 수정과 관련

렌더링

클라이언트가 각 프레임에 소비하는 시간의 상당 부분은 현재 프레임에서 장면을 렌더링하는 데 사용됩니다.서버는 렌더링을 하지 않으므로 이 섹션은 클라이언트에만 전용됩니다.

드로우 콜 실행

드로우 콜은 엔진에서 GPU로 렌더링할 내용에 대한 지침 집합입니다.드로우 콜은 상당한 오버헤드가 있습니다.일반적으로 프레임당 드로우 호출이 적을수록 프레임 렌더링에 소요되는 계산 시간이 줄어듭니다.

Studio에서 렌더링 스탯 > 타이밍 항목으로 현재 발생하는 드로우 호출 수를 확인할 수 있습니다.클라이언트에서 렌더링 통계 보기 를 누르면 ShiftF2에서 클라이언트에서 렌더링 통계를 볼 수 있습니다.

지정된 프레임에서 장면에 그려야 하는 개체가 많을수록 GPU에 더 많은 드로잉 호출이 수행됩니다.그러나 Roblox 엔진은 동일한 텍스처 특성을 가진 동일한 메쉬를 단일 드로우 호출로 축소하기 위해 instancing이라는 프로세스를 사용합니다특히, 동일한 MeshId 을 가진 여러 메쉬가 단일 드로우 호출에서 처리되는 경우:

기타 일반적인 문제

  • 과도한 개체 밀도 - 많은 개체가 높은 밀도로 집중되면 장면의 이 영역을 렌더링하는 데 더 많은 드로우 호출이 필요합니다.맵의 특정 부분을 보면서 프레임 속도가 떨어지는 것을 발견하면, 이 영역의 개체 밀도가 너무 높다는 좋은 신호일 수 있습니다.

    데칼, 텍스처 및 입자와 같은 개체는 일괄 처리되지 않으며 추가 드로우 호출을 소개합니다장면에서 이러한 개체 유형에 특별히 주의를 기울이십시오.특히, ParticleEmitters 속성의 변경은 성능에 극적인 영향을 미칠 수 있습니다.

  • 놓친 인스턴스 기회 - 종종 장면에는 메쉬를 여러 번 복제한 동일한 메쉬가 포함되지만, 메쉬의 각 복사본에는 서로 다른 메쉬 또는 텍스처 자산 ID가 있습니다.이렇게 하면 인스턴스화가 방지되고 불필요한 드로우 호출이 발생할 수 있습니다.

    이 문제의 일반적인 원인은 개별 자산이 Roblox에 가져와 조립 후에 복제되는 것이 아니라 전체 장면을 한 번에 가져와 조립하는 경우입니다.

  • 과도한 개체 복잡성 - 드로우 콜 수만큼 중요하지는 않지만, 장면에 있는 삼각형 수는 프레임이 렌더링하는 데 걸리는 시간을 영향을 미칩니다.매우 많은 매우 복잡한 메쉬가 있는 장면은 매우 많은 메쉬에 속성 이 설정되어 있는 장면과 마찬가지로 일반적인 문제입니다.

  • 과도한 그림자 캐스팅 - 그림자를 처리하는 것은 비용이 많이 드는 과정이며, 그림자를 캐스팅하는 빛 개체의 높은 수와 밀도(또는 그림자에 영향을 미치는 작은 부품의 높은 수와 밀도)를 포함하는 맵은 성능 문제가 발생할 수 있습니다.

  • 높은 투명도 오버드로잉 - 부분 투명도를 가진 개체를 서로 가까이 배치하면 엔진이 겹치는 픽셀을 여러 번 렌더링하도록 강요하여 성능에 영향을 줄 수 있음이 문제를 식별하고 해결하는 자세한 내용은 레이어 투명도 삭제를 참조하십시오.

해결책

  • 동일한 메쉬 인스턴스화 및 고유 메쉬 수 줄이기 - 모든 동일한 메쉬에 동일한 기본 자산 ID가 있는지 확인하면 엔진이 단일 드로우 호출에서 인식하고 렌더링할 수 있습니다.매핑에서 각 메쉬를 한 번만 업로드하고 나머지는 Studio에서 복제하여 전체 맵을 가져오는 대신 다시 사용하도록 하고, 엔진에서 동일한 메쉬가 서로 다른 콘텐츠 ID를 가지고 있고 고유한 자산으로 인식되도록 하는 것이 중요합니다.패키지는 개체 재사용을 위한 유용한 메커니즘입니다.
  • 정리 - 정리는 최종 렌더링 프레임에 영향을 주지 않는 개체에 대한 드로우 호출을 제거하는 과정을 설명합니다.기본적으로 엔진은 카메라의 시야 밖에 있는 개체에 대한 드로우 콜을 건너뛰지만, 다른 개체에 의해 시야가 가려진 개체에 대한 드로우 콜은 건너뛰지 않습니다(차단 가리기).장면에 많은 드로우 호출이 있는 경우, 다음과 같은 일반 전략을 적용하여 런타임에 모든 프레임에 대해 자체 추가 선별을 동적으로 구현하는 것을 고려하십시오:
    • 카메라나 설정으로부터 멀리 있는 MeshPartBasePart를 숨기십시오.
    • 실내 환경의 경우 현재 어떤 사용자도 사용하지 않는 개체를 숨기는 방 또는 포털 시스템을 구현합니다.
  • 렌더링 정확도 줄이기 - 렌더링 정확도를 자동으로 또는 성능으로 설정합니다.이렇게 하면 메쉬가 더 복잡하지 않은 대안으로 돌아갈 수 있으므로 그려야 하는 폴리곤 수가 줄어듭니다.
  • 적절한 부품과 조명 개체에서 그림자 캐스팅 비활성화 - 장면의 그림자 복잡성은 조명 개체와 부품에서 그림자 캐스팅 속성을 선택적으로 비활성화하여 줄일 수 있습니다.이는 편집 시간에 또는 런타임에 동적으로 수행할 수 있습니다.일부 예시는 다음과 같습니다.
    • BasePart.CastShadow 속성을 사용하여 그림자가 표시될 가능성이 적은 작은 부품에서 그림자 캐스팅을 비활성화합니다.사용자의 카메라에서 멀리 떨어진 부품에만 적용되는 경우에 특히 효과적입니다.

    • 가능하면 이동 중인 개체의 그림자를 비활성화하십시오.

    • 개체가 그림자를 던져야 하지 않는 경우 라이트 인스턴스에서 Light.Shadows

    • 조명 인스턴스의 범위와 각도를 제한합니다.

    • 조명 인스턴스를 더 적게 사용합니다.

마이크로프로파일러 스코프

영역관련 계산
준비 및 수행전체 렌더링
수행/장면/계산 조명 수행라이트 그리드 및 쉐도우 업데이트
라이트그리드 CPU복셀 조명 그리드 업데이트
쉐도우맵 시스템쉐도우 맵핑
수행/시나리오/업데이트뷰렌더링 및 파티클 업데이트 준비
수행/장면/렌더뷰렌더링 및 후처리

네트워크 및 복제 Networking and replication

네트워킹과 복제는 서버와 연결된 클라이언트 간에 데이터를 전송하는 프로세스를 설명합니다.모든 프레임에서 클라이언트와 서버 사이에 정보가 전송되지만, 더 많은 정보는 더 많은 컴퓨팅 시간이 필요합니다.

공통 문제

  • 과도한 원격 트래픽 - RemoteEvent 또는 RemoteFunction 개체를 통해 많은 양의 데이터를 보내거나 너무 자주 호출하면 각 프레임마다 들어오는 패킷을 처리하는 데 많은 CPU 시간이 소비됩니다.일반적인 오류에는 다음이 포함됩니다:

    • 복제할 필요가 없는 모든 프레임에서 데이터를 복제합니다.
    • 제한 장치 없이 사용자 입력에 따라 데이터를 복제하는 중.
    • 필요한 것보다 더 많은 데이터를 전송합니다.예를 들어, 플레이어가 아이템을 구매할 때 아이템의 세부 정보가 아닌 전체 인벤토리를 보내는 것입니다.
  • 복잡한 인스턴스 트리 생성 또는 제거 - 서버에서 데이터 모델에 변경이 적용되면 연결된 클라이언트에 복제됩니다.즉, 맵처럼 실행 시간에 큰 인스턴스 계층을 만들고 파괴하는 것이 네트워크 집약적일 수 있습니다.

    여기에서 일반적인 범인은 리그에서 애니메이션 편집기 플러그인에 의해 저장된 복잡한 애니메이션 데이터입니다.게임이 게시되고 애니메이션 모델이 정기적으로 복제되기 전에 이들이 제거되지 않으면 많은 양의 데이터가 불필요하게 복제됩니다.

  • 서버 측 트위언 서비스 - TweenService를 사용하여 개체 서버 측에서 트위닝하면, 트위닝된 속성이 각 클라이언트에 매 프레임마다 복제됩니다.이렇게 하면 클라이언트의 대기 시간이 변동함에 따라 청소년이 긴장하게 되는 것뿐만 아니라 불필요한 네트워크 트래픽을 많이 발생시킵니다

해결책

불필요한 복제를 줄이기 위해 다음 전략을 사용할 수 있습니다:

  • 원격 이벤트를 통해 한 번에 대량의 데이터를 보내지 않도록 주의하십시오 .대신 더 낮은 주파수에서만 필요한 데이터만 전송합니다.예를 들어, 캐릭터의 상태에 대해서는 모든 프레임이 아닌 변경될 때 복제합니다.
  • 맵처럼 복잡한 인스턴스 트리를 조각으로 나누어 작업을 여러 프레임에 복제하도록 배포 * 애니메이션 메타데이터 정리 , 특히 리그의 애니메이션 디렉토리는 가져온 후 정리
  • 불필요한 인스턴스 복제 제한 , 특히 서버가 생성되는 인스턴스에 대해 알 필요가 없는 경우포함 내용:
    • 폭발이나 마법 주문과 같은 시각적 효과.서버는 결과를 결정하기 위해 위치만 알면 되고, 클라이언트는 로컬로 시각적 요소를 생성할 수 있습니다.
    • 1인칭 아이템 뷰 모델.
    • 서버가 아닌 클라이언트의 중간 개체.

마이크로프로파일러 스코프

영역관련 계산
프로세스 패킷이벤트 호출 및 속성 변경과 같은 들어오는 네트워크 패킷 처리
대역 할당 및 발신자 실행서버와 관련된 외부 이벤트

자산 메모리 사용량

크리에이터가 클라이언트 메모리 사용량을 개선하기 위해 사용할 수 있는 가장 큰 영향 메커니즘은 인스턴스 스트리밍을 활성화하는 것입니다.

인스턴스 스트리밍

인스턴스 스트리밍은 필요하지 않은 데이터 모델 부분을 선택적으로 로드하여 부하 시간이 크게 줄어들고 메모리 부족으로 인해 클라이언트가 충돌을 방지할 수 있는 능력이 향상됩니다.

메모리 문제를 경험하고 인스턴스 스트리밍이 비활성화되어 있는 경우, 특히 3D 세계가 크면 경험을 업데이트하여 지원하는 것이 좋습니다.인스턴스 스트리밍은 3D 공간에서의 거리를 기반으로 하므로 더 큰 세계는 자연스럽게 더 많이 혜택을 얻습니다.

인스턴스 스트리밍이 활성화되면 공격성을 높일 수 있습니다. 예를 들어, 다음을 고려하십시오:

  • 영구적인 스트리밍 무결성 StreamingIntegrity 사용 감소.
  • 스트리밍 반경 을 줄이는 중 .

스트리밍 옵션과 그 이점에 대한 자세한 정보는 스트리밍 속성에 참조하십시오.

기타 일반적인 문제

  • 자산 복제 - 일반적인 실수는 동일한 자산을 여러 번 업로드하여 서로 다른 자산 ID로 이어지는 것입니다.이로 인해 동일한 콘텐츠가 여러 번 메모리에 로드되는 경우가 있습니다.
  • 과도한 자산 볼륨 - 자산이 동일하지 않은 경우에도 동일한 자산을 재사용하고 메모리를 절약할 기회를 놓치는 경우가 있습니다.
  • 오디오 파일 - 오디오 파일은 특히 경험의 일부만 필요로 하는 것이 아니라 모두를 클라이언트에 한 번에 로드하는 경우 메모리 사용에 놀라운 기여자가 될 수 있습니다.전략의 경우 로드 시간을 참조하십시오
  • 고해상도 텍스처 - 텍스처의 그래픽 메모리 소비는 디스크에 있는 텍스처의 크기와 관련이 없으며, 텍스처의 픽셀 수에 관련이 있습니다.
    • 예를 들어, 1024x1024 픽셀 텍스처는 512x512 텍스처의 그래픽 메모리를 4배 소비합니다
    • Roblox에 업로드된 이미지는 고정 형식으로 변환되므로 픽셀당 더 적은 바이트를 사용하는 색상 모델로 이미지를 업로드할 때 메모리 이점이 없습니다.마찬가지로, 업로드하거나 알파 채널을 이미지에서 제거하기 전에 이미지를 압축하거나 알파 채널을 필요로 하지 않는 이미지에서 알파 채널을 제거하면 디스크의 이미지 크기가 줄어들지만, 개선되지 않거나 메모리 사용량이 약간만 개선됩니다.엔진은 일부 장치에서 텍스처 해상도를 자동으로 다운스케일링하지만, 다운스케일링의 범위는 장치 특성에 따라 달라지며 과도한 텍스처 해상도는 여전히 문제를 일으킬 수 있습니다.
    • 개발자 콘솔의 그래픽 텍스처 카테고리를 확장하여 지정된 텍스처의 그래픽 메모리 소비량을 식별할 수 있습니다.You can identify the graphics memory consumption for a given texture by expanding the GraphicsTexture category in the Developer Console .

해결책

  • 자산을 한 번만 업로드하기 - 개체 간에 동일한 자산 ID를 재사용하고 메쉬 및 이미지와 같은 동일한 자산이 여러 번 별도로 업로드되지 않도록 합니다.
  • 중복 자산 찾아 수정 - 다른 ID로 여러 번 업로드된 동일한 메쉬 부품과 텍스처를 찾으십시오.
    • 자산의 유사성을 자동으로 감지하는 API가 없더라도 장소에서 모든 이미지 자산 ID(수동으로 또는 스크립트로)를 수집하고, 외부 비교 도구를 사용하여 비교하고 비교할 수 있습니다.
    • 메쉬 부품의 경우 가장 좋은 전략은 고유한 메쉬 ID를 가져와 크기별로 구성하여 복제품을 수동으로 식별하는 것입니다.
    • 서로 다른 색상에 대해 별도의 텍스처를 사용하는 대신, 단일 텍스처를 업로드하고 SurfaceAppearance.Color 속성을 사용하여 다양한 틴트를 적용하십시오
  • 맵에서 자산 별도 가져오기 - 한 번에 전체 맵을 가져오는 대신, 맵에서 자산을 가져와 개별적으로 재구성하고 재건합니다.3D 가져오기는 메쉬를 복제하지 않으므로, 많은 개별 바닥 타일이 있는 큰 맵을 가져오더라도 각 타일은 별도의 자산으로 가져오됩니다(비록 그것들이 복제품이더라도).이로 인해 각 메시가 개별적으로 처리되고 메모리와 드로우 호출을 차지하기 때문에 라인 전체에서 성능 및 메모리 문제가 발생할 수 있습니다.
  • 이미지의 픽셀을 필요한 최대 수로 제한합니다. 이미지가 화면에서 많은 물리적 공간을 차지하지 않는 한, 일반적으로 최대 512x512픽셀이 필요합니다.대부분의 미니어처 이미지는 256x256픽셀보다 작아야 합니다。
  • 트림 시트 사용 으로 3D 맵에서 최대 텍스처 재사용을 보장합니다.트림 시트를 만드는 단계와 예제는 트림 시트 만들기에 참조하십시오.

로딩 시간

많은 경험에서는 사용자 지정 로딩 화면을 구현하고 ContentProvider:PreloadAsync() 메서드를 사용하여 자산을 요청하여 이미지, 사운드 및 메쉬가 배경에서 다운로드되도록 합니다.

이 방법의 장점은 팝인 없이 경험의 중요한 부분이 완전히 로드되도록 보장할 수 있다는 것입니다.그러나 일반적인 오류는 실제로 필요한 것보다 더 많은 자산을 미리 로드하기 위해 이 메서드를 과도하게 사용하는 것입니다.

나쁜 연습의 예는 전체 를 로드하는 것입니다Workspace.이로 인해 텍스처가 팝업되는 것을 방지할 수는 있지만 로드 시간이 크게 증가합니다.

대신, 필요한 상황에서만 ContentProvider:PreloadAsync()를 사용하십시오, 이에는 다음이 포함됩니다:

  • 로딩 화면에 있는 이미지.
  • 버튼 배경 및 아이콘과 같은 경험 메뉴의 중요 이미지.
  • 시작 또는 생성 영역의 중요 자산.

대량의 자산을 로드해야 하는 경우 로딩 건너뛰기 버튼을 제공하는 것이 좋습니다.