Unity Dots理论学习-1.关于性能

如果你是一个有经验的游戏开发者,那么你知道在目标平台上进行性能优化是贯穿整个开发周期的任务。也许你的游戏在高端PC上运行得很好,但在低端移动平台上,帧率是不是会慢很多,导致明显的卡顿?加载时间是不是过长,玩家每次走过门时,游戏就会卡住几秒钟?在这种情况下,不仅当前的游戏体验不尽如人意,游戏本身也因此被阻止添加更多功能:更多的环境细节和规模、游戏机制、角色和动作、视觉效果等。

问题的根源是什么?在许多项目中,问题出在渲染:Texture过大、Mesh过于复杂、Shader过于消耗资源,或者批处理、剔除和LOD的使用不当。

另一个常见的陷阱是过度使用复杂的mesh collider,这会大大增加物理模拟成本。或者,你编写的C#代码可能占用了过多的CPU时间,导致游戏的现实模拟本身很慢。

那么,如何编写快速的,至少是不迟缓的代码?

在过去的几十年里,PC游戏开发者通常通过“静候时代到来”来解决这个问题。从20世纪70年代到21世纪,CPU的单线程性能近乎每几年翻一番(摩尔定律),因此一款PC游戏在生命周期内“自动”变得更快。然而,在过去的二十年里,CPU单线程性能的提升相对较为平缓。相反,CPU的核心数量不断增加,甚至像智能手机这样的便携设备也开始配备多核。

此外,高端与低端游戏设备之间的性能差距也在逐步加大,很多玩家使用的是已经几年没更新的硬件。等待更快的硬件似乎不再是一个可行的策略。

那么,问题应该是:“为什么我的代码在CPU上运行时会这么缓慢?”有几个常见的陷阱:

GC引起的开销和明显停滞:这是因为垃圾回收器作为自动内存管理器,负责管理应用程序内存的分配和释放。垃圾回收不仅会导致CPU和内存的开销,还可能在执行过程中暂停代码的运行,通常暂停时间为几毫秒。用户可能会感受到GC引起的帧率波动或更为明显的卡顿。

编译器生成的机器码不优化:某些编译器生成的代码优化程度远低于其他编译器,且优化效果在不同平台上可能有所不同。

CPU核心利用不充分:虽然现在最低端的设备也配有多核CPU,但许多游戏仍将大部分逻辑保持在主线程上,因为编写多线程代码通常很困难且容易出错。

数据不符合缓存友好性:从缓存中访问数据比从主存中获取数据要快得多。然而,从主存访问数据可能需要CPU等待数百个CPU周期,所以我们更希望CPU尽可能地从缓存中读写数据。

最简单的方式是按顺序读取和写入内存,因此,最符合缓存友好的方式是将数据存储在数组中。但是,如果数据在内存中是不连续的分散存储,那么访问它将会导致大量的缓存未命中,进而需要从更慢的主存中获取。

代码不符合缓存友好性:同上一条,当代码执行时,如果它尚未加载到缓存中,它必须从主存中加载。一种策略是尽量减少函数调用的次数,以减少从主存加载的频率。例如,与其在多个代码块调用某个函数,不如在一个代码块中调用它,这样代码每次执行最多只需要加载一次。

代码过于抽象:抽象通常会导致数据和代码复杂性增加,从而加剧上述问题:没有GC的内存管理变得更加困难;编译器可能无法进行有效优化;安全且高效的多线程编程变得更加困难,而且数据和代码也可能变得不太符合缓存友好性。除此之外,抽象往往会分散性能成本,使得整个代码运行更慢,导致没有明显的性能瓶颈可以优化。

以上所有问题在Unity项目中都很常见。让我们更具体地来看一下这些问题:

虽然C#允许手动分配不会被GC的对象,但大多数Unity项目中的C#代码是使用会被GC的类实例。 实际上,Unity开发者长期通过“对象池”(主要优点是高效地重复使用来自预分配池的对象,消除了频繁创建和销毁对象的需要)来缓解这个问题(尽管对象池的使用可以说违背了最初使用能自动垃圾回收的语言的目的)。

在Unity编辑器中,C#代码通常通过Mono编译器编译成机器码。 对于独立构建,你通常可以使用IL2CPP(将C#中间语言转编译为C++)获得更好的效果,但这也带来一些缺点,比如更长的构建时间、游戏更难支持mod修改。

通常,Unity项目会将所有代码都运行在主线程上,部分原因是这是Unity提供的最简单方式:

  1. Unity的部分事件函数,比如MonoBehaviour的Update(),都是在主线程中运行的。
  2. 大多数Unity API只能在主线程中才能保证安全调用。

大部分Unity项目中的数据结构通常是将一堆随机对象分散在内存中,这导致缓存命中率非常低。 再次强调,这部分是因为Unity使得以下操作变得容易:GameObject及其组件都是单独分配的,因此它们往往会分散存储在内存的不同部分。

  1. 传统Unity项目中的代码往往不符合缓存友好性:
  2. 传统的C#和Unity的API鼓励使用面向对象的编程方式,这种风格倾向于产生大量小型方法和复杂的调用链。与数据导向的编程方式不同,这种方式并不十分符合硬件优化。

每个MonoBehaviour的事件函数是单独调用的,这些调用不一定会按MonoBehaviour类型进行分组。例如,如果你有1000个Monster MonoBehaviour,每个Monster会单独更新,并不一定会与其他Monster一起更新。
传统C#和许多Unity API的面向对象方式通常导致过多的抽象层。这种抽象层的代码通常会导致效率低下,且很难解耦和隔离。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/65673.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库概念(MySQL第一期)

p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解 目录 数据库就是管理数据的仓库 数据库:DataBase(DB),是存储数据的仓库,数据是有组织的进行存储 数据库管理系统:DataBase Management S…

【ES6复习笔记】ES6的模块化(18)

模块化的概念 模块化是指将一个复杂的系统分解为多个模块,每个模块完成一个特定的功能,模块之间通过接口进行通信。模块化的目的是提高代码的可读性、可维护性和可重用性。 模块化规范产品, ES6 之前的模块化规范有: CommonJS …

C语言初阶习题【19】三子棋游戏

1.实现三子棋游戏 2.思路 我们把游戏实现部分放在game.c和game.h中,把游戏的测试代码放到test.c中 main函数在test.c中。 2.1 test.c中 先写main 函数,在main函数中调用test函数。 int main() {test();return 0; }test.c函数实现让玩家进行选择是否…

金融租赁系统的创新发展与市场竞争力提升探讨

内容概要 随着经济的快速发展,金融租赁系统逐渐成为金融市场中不可或缺的一环。它不仅提供了灵活的资金解决方案,还促进了企业的资本结构优化与资源配置效率。因此,了解该系统的市场背景与发展现状至关重要。 在现今环境下,新兴…

设计模式与游戏完美开发(2)

更多内容可以浏览本人博客:https://azureblog.cn/ 😊 该文章主体内容来自《设计模式与游戏完美开发》—蔡升达 第二篇 基础系统 第四章 游戏主要类——外观模式(Facade) 一、游戏子功能的整合 一个游戏程序常常由内部数个不同的…

linux自动化批量分发SSH密钥同时批量测试SSH连接教程(包含自动化脚本代码)

1、检查端口 检查分发对象22端口是否打开 nmap -p22 ip地址如果要批量检查端口可以参考我写的这篇文章:linux自动化一键批量检查主机端口 2、命令行分发密钥原理 Linux分发密钥原理主要涉及SSH(Secure Shell)协议,该协议用于…

OpenHarmony源码编译后烧录镜像教程,RK3566鸿蒙开发板演示

本文介绍瑞芯微主板/开发板编译OpenHarmony源码后烧录镜像的教程,触觉智能Purple Pi OH鸿蒙开发板演示。搭载了瑞芯微RK3566四核处理器,树莓派卡片电脑设计,支持开源鸿蒙OpenHarmony3.2-5.0系统,适合鸿蒙开发入门学习。 编译源码…

【GO基础学习】gin框架路由详解

文章目录 gin框架路由详解(1)go mod tidy(2)r : gin.Default()(3)r.GET()路由注册 (4)r.Run()路由匹配 总结 gin框架路由详解 先创建一个项目,编写一个简单的demo&#…

vue之axios基本使用

文章目录 1. axios 网络请求库2. axiosvue 1. axios 网络请求库 <body> <input type"button" value"get请求" class"get"> <input type"button" value"post请求" class"post"> <!-- 官网提供…

使用 Spring Boot 实现文件上传:从配置文件中动态读取上传路径

使用 Spring Boot 实现文件上传&#xff1a;从配置文件中动态读取上传路径 一、前言二、文件上传的基本概念三、环境准备1. 引入依赖2. 配置文件设置application.yml 配置示例&#xff1a;application.properties 配置示例&#xff1a; 四、编写文件上传功能代码1. 控制器类2. …

AI 神经网络在智能家居场景中的应用

在科技持续进步的当下&#xff0c;智能家居领域正经历着深刻变革&#xff0c;AI 神经网络技术的融入成为推动这一变革的关键力量&#xff0c;为家居生活带来了诸多显著变化与提升&#xff0c;本文将几种常见的AI算法应用做了一下总结&#xff0c;希望对物联网从业者有所帮助。 …

ubuntu快速入门

1.进入某个文件夹 cd workspace/2.tab自动补全 3.列出当前文件夹所有文件 ls列出所有文件包括隐藏文件 ls -a 4.创建文件夹 mkdir linuxLearn 5.创建文件 gedit command.sh在commmand.sh键入 echo hello echo hi? echo how are you? PS:touch hello.txt(也可以创建新…

Day56 图论part06

108.冗余连接 并查集应用类题目,关键是如何把题意转化成并查集问题 代码随想录 import java.util.Scanner;public class Main{public static void main (String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();DisJoint disjoint = new DisJo…

优化 invite_codes 表的 SQL 创建语句

-- auto-generated definition create table invite_codes (id int auto_incrementprimary key,invite_code varchar(6) not null comment 邀请码&#xff0c;6位整数&#xff0c;确保在有效期内…

FATE-LLM简介;FATE-LLM集成了多种参数高效微调方法

FATE-LLM简介 FATE-LLM是一个支持联邦大语言模型训练的框架,其架构及核心技术原理如下: 架构概述 FATE-LLM主要由模型层、参数高效微调层、隐私保护与安全机制、通信与聚合模块等组成,致力于在保护数据隐私的前提下,利用联邦学习技术整合各方数据与算力资源,提升大语言模…

小程序租赁系统构建指南与市场机会分析

内容概要 在当今竞争激烈的市场环境中&#xff0c;小程序租赁系统正崭露头角&#xff0c;成为企业转型与创新的重要工具。通过这个系统&#xff0c;商户能够快速推出自己的小程序&#xff0c;无需从头开发&#xff0c;节省了大量时间和资金。让我们来看看这个系统的核心功能吧…

数据库系列之分布式数据库下误删表怎么恢复?

数据的完整性是数据库可用性的基本功能&#xff0c;在实际应用数据库变更操作过程中可能因为误操作导致误删表或者truncate操作影响业务的正常访问。本文介绍了分布式数据库中在误删表场景下的数据恢复方案&#xff0c;并进行了对比。 1、数据库误删表恢复方案 应用数据的完整…

论文阅读:Towards Faster Deep Graph Clustering via Efficient Graph Auto-Encoder

论文地址&#xff1a;Towards Faster Deep Graph Clustering via Efficient Graph Auto-Encoder | ACM Transactions on Knowledge Discovery from Data 代码地址&#xff1a; https://github.com/Marigoldwu/FastDGC 摘要 深度图聚类&#xff08;Deep Graph Clustering, DGC…

Python爬虫教程——7个爬虫小案例(附源码)_爬虫实例

本文介绍了7个Python爬虫小案例&#xff0c;包括爬取豆瓣电影Top250、猫眼电影Top100、全国高校名单、中国天气网、当当网图书、糗事百科段子和新浪微博信息&#xff0c;帮助读者理解并实践Python爬虫基础知识。 包含编程资料、学习路线图、源代码、软件安装包等&#xff01;【…

BMS存储模块的设计

目的 电池管理系统中存在着数据本地存储的要求&#xff0c;保证控制器重新上电后能够根据存储器中的一些参数恢复控制状态&#xff0c;和信息的下电存储1.继电器故障信息的存储。2. 系统性故障的存储。3.SOC、SOH相关信息的存储。4.均衡参数的存储。5.系统时间信息。6.出厂信息…