Unity性能优化
前言
当游戏开发使用传统的OPP(面向对象编程)面对大量的Game object时FPS会显著降低,而使用Dots(面向数据编程)性能依旧很好
计算机内存基础
CPU自身有三级高速缓存,L1,L2,L3,其中CPU访问(L1)缓存最快,容量最小,第三级(L3)缓存最慢,容量最大。
内存是指CPU拿取数据的起源点,CPU访问内存所需的时钟周期远大于访问高速缓存所需的时钟周期
CPU处理数据的速度非常快,因此需要高速缓存区避免CacheMiss高速缓存缺失,以确保CPU一直在运行(未休息)
CPU操作数据会先从一,二,三级缓存中取得数据,如果数据不在三级缓存,就需要寻址内存中的数据
Dots(Data Oriented Tech Stack) 面向数据的技术堆栈
是一系列的集合
Entity Component System(ECS) :实体组件系统
Burst Compiler :Burst编译器 ,也是LLVM编译器
Job System :任务系统
masmatic:数学库
ECS
ECS即实体(Entity),组件(Component),系统(System),其中Entity,Component皆为纯数据向的类,System负责操控他们,这种模式会一定程度上优化我们的代码速度。
- Entities:游戏中的事物,但在ECS中他只作为一个Id
- Components:与Entity相关的数据,但是这些数据应该由Component本身而不是Entity来组织。(这种组织上的差异正是面向对象和面向数据的设计之间的关键差异之一)。
- Systems:Systems是把Components的数据从当前状态转换为下一个状态的逻辑,但System本身应当是无状态的。例如,一个system可能会通过他们的速度乘以从前一帧到这一帧的时间间隔来更新所有的移动中的entities的位置。
为什么ECS架构会加快性能?
将传统游戏对象杂乱无序的组件归类,当读取数据时无法从L1中找到,先从这一堆杂乱无序的内中找到需要的内存,然后将它读取并且移动到L1缓存中,移除L1不需要的数据(因为内存容量小),这个过程就会造成CacheMiss
而当我们用ECS的架构组织数据,它会将相同组件Component 整齐排列在内存中,当我们开始遍历相同组件时并不需要一个个从内存中读取,可以指定一个长度一次性全读进来放入缓存中,因此避免了CacheMiss
因此ECS模式无疑更加适合现代CPU架构
Burst Complier
Burst是使用LLVM从IL/.NET字节码转换为高度优化的本机代码的编译器。它作为Unity package发布,并使用Unity Package Manager集成到Unity中。 它全盘接管了我们编写的新C#编译工作,可以让我们在特定模式下无痛写出高性能代码。
JobSystem
它可以让我们无痛写出多线程并行处理的代码,并且内部配合Burst Complier进行SIMD优化。 你可以把JobSystem和Unity的ECS一起用,两者配合可以让为所有平台生成高性能机器代码变得简单。
masmatic
一个C#数学库提供矢量类型和数学函数(类似Shader里的语法)。由Burst编译器用来将C#/IL编译为高效的本机代码。
DOTS配置
官方文档
注意unity版本
要使用 Entities 包,必须安装 Unity 版本 2022.3.0f1 及更高版本
必须使用可编程渲染管线:
内置渲染管线(Built-in Render Pipeline)不是可编程渲染管线
URP (Universal Render Pipeline)通用渲染管线,可编程
(High Definition Render Pipeline)(HDRP)高清渲染管线。可编程
安装包
- com.unity.entities工具包:包括ECS,Burst,Job System,masmatic
- com.unity.entities.graphics渲染entity
- com.unity.physics:ECS物理
- 通过window->packageManager->'+'加号->install package by name->install搜索
- 注意所有包的版本要一致,如果无法安装指定版本通过:
- 工程文件Packages/manifest.json中手动修正版本,重启引擎
IDE
版本要更新
unity设置
Edit > Project Settings > Editor菜单,然后启用 Enter Play Mode Options 设置,但禁用 Reload Domain 和 Reload Scene
c#Attribute特性
反射:
如果让你在不修改源代码的情况下,通过一个函数(参数为类类型),运行时获取所有参数为空的公有成员方法,这是不可能的
但是如果可以修改类呢?
- 可以让每一个类继承Object基类,每个类都手写一个FuncData的表(所有MetaData元数据(FuncData,PropData)数据表)
- 每个类都重写基类的public FuncData[] getFuncData();方法
这样就可以运行时获取
Attribute:
比如我们通过反射可以快速查找一个类是否仅包含数据
那如果我想要对特定类不同控制?
Attribute是反射的扩充,目的是在不破坏原有代码的 情况下,在代码的元数据上附加一些信息
[……]语法:
实际是调用一个继承Attribute类的特性(自定义/内置)的构造
Attribute:
在运行时动态地获取和操作类和对象的信息(添加元数据),提供了一种声明性方式[……]来指定代码的行为或其他相关信息,可以被应用于程序集、类、方法、属性、事件等
运行时:编译期间无法确定的,接收非特定对象,结果会根据具体对象而不同
创建一个custom自定义特性Attribute:
继承自 System.Attribute
类,
其中AttributeUsage
内置特性,用于指定一个自定义特性可以应用于哪些代码元素上可以控制特性的有效性目标(如类、方法、属性等)以及是否允许特性被多次应用于同一个目标。
AttributeTargets
:指定特性可以应用于哪些目标(如类、方法、属性等)。Inherited
:指定特性是否可以被派生类继承。AllowMultiple
:指定是否允许在同一目标上多次应用该特性。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class MyCustomAttribute : Attribute
{ public string Description { get; } public MyCustomAttribute(string description) { Description = description; }
}
使用:通常通过方括号 []
语法使用特性:
[MyCustomAttribute("This is a class description")]
public class MyClass
{ [MyCustomAttribute("This is a method description")] public void MyMethod() { // Method implementation }
}
在运行时,可以使用反射(attribute基类)来访问特性并读取其值:
通过Attribute.GetCustomAttribute获取到了,指定类关联的特性类,
var type = typeof(MyClass); // 获取类上的MyCustomAttribute
var classAttribute = (MyCustomAttribute)Attribute.GetCustomAttribute(type, typeof(MyCustomAttribute));
Console.WriteLine(classAttribute.Description); // 获取方法上的MyCustomAttribute
var method = type.GetMethod("MyMethod");
var methodAttribute = (MyCustomAttribute)Attribute.GetCustomAttribute(method, typeof(MyCustomAttribute));
Console.WriteLine(methodAttribute.Description);
常见的 C# 内置特性:
Obsolete
:标记一个程序元素为过时。Serializable
:指示一个类可以被序列化。DllImport
:用于声明非托管代码的外部方法。- Conditional:允许根据编译符号的存在与否来控制方法的调用。
C#常见内置特性功能:
- 查询类的信息:获取类的名称、基类、实现的接口、包含的字段、属性、方法等。
- 创建对象:即使不知道类的具体类型,也可以通过反射在运行时创建该类的对象实例。
- 调用方法:根据方法名和参数类型,在运行时调用对象的方法。
- 访问字段和属性:读取或修改对象的字段和属性值,即使这些字段和属性在编译时是未知的。
其他性能优化
Object Pooling对象池
用于减少对象Instantiate()创建和destroy()销毁的性能开销,减少创建销毁api的调用
维护一个list<>
创建-》如果pool中没有obj,那么就instantiate,如果有就从池内取出对象
销毁—》使用完成放回池内
组合设计模式
- MVC(Model-View-Controller)
- MVP(Model-View-Presenter)
- MVVM(Model-View-ViewModel)
实现低耦合
相关文章:
Unity性能优化
前言 当游戏开发使用传统的OPP(面向对象编程)面对大量的Game object时FPS会显著降低,而使用Dots(面向数据编程)性能依旧很好 计算机内存基础 CPU自身有三级高速缓存,L1,L2,L3,其中CPU访问(L1…...

MyHdfs代码分享
关于hdfs协议层相关的的解析已经比较全面,但是大多的分析停留在理论层面。为此笔者通过对hadoop源码的整理,完成了myhdfs项目。此项目有个特点是不依赖于任何hadoop的maven包,但却可以作为原生的hadoop客户端的server。项目暂时已经完成了rpc…...

Java网络编程-简单的API调用
Get请求 - 无参数 安装依赖库 首先需要安装一个库: Okhttp3,这是一个非常流行的 HTTP 库,可以简单、快速的实现 HTTP 调用。 安装 Okhttp3 的方式是在 pom.xml 文件中增加依赖: <!-- https://mvnrepository.com/artifact/c…...

论文笔记(五十)Segmentation-driven 6D Object Pose Estimation
Segmentation-driven 6D Object Pose Estimation 文章概括摘要1. 引言2. 相关工作3. 方法3.1 网络架构3.2 分割流3.3 回归流3.4 推理策略 4. 实验4.1 评估 Occluded-LINEMOD4.1.1 与最先进技术的比较4.1.2 不同融合策略的比较4.1.3 与人体姿态方法的比较 4.2 在YCB-Video上的评…...

微服务的一些基本概念
目录 1 概述1.1 微服务架构的特征1.2 微服务架构示例 2 微服务与单体式架构2.1 什么是单体式架构?2.2 单体式架构的优点2.3 单体式架构的缺点 3 什么是微服务?3.1 微服务的优点3.2 微服务的缺点 4 如何构建微服务4.1 从单体式开始4.2 以正确的方式组织团…...

el-table修改指定列字体颜色 ,覆盖划过行的高亮显示文字颜色
修改指定列字体颜色 ,覆盖划过行的高亮显示文字颜色 代码如下: <div class"c1"><el-table:data"tableData"striperow-class-name"custom-table-row"style"width:100%"cell-mouse-enter"lightFn"cell-…...

java高频面试题汇总
Java 基础 Java 中的序列化和反序列化是什么? 序列化是将 Java 对象转换为字节流的过程,以便可以将其存储在文件中或通过网络进行传输。反序列化则是将字节流恢复为 Java 对象的过程。通过实现 Serializable 接口,Java 对象可以支持序列化。…...

Docker安装ocserv教程(效果极佳)
本章教程,介绍如何在Debain系统上安装ocserv。安装方式是使用Docker方式部署。 一、安装Docker curl -sSL https://file.ewbang.com/docker/debian/install_docker.sh -o install_docker.sh && bash install_docker.sh二、拉取镜像 docker pull tommylau/ocserv...

【数据结构与算法】第3课—数据结构之单链表
文章目录 1. 什么是链表2. 单链表2.1 单链表的初始化和打印2.2 单链表的尾插和头插2.3 单链表的尾删和头删2.4 单链表查找节点2.5 单链表在指定位置之前/之后插入数据2.6 单链表删除节点和删除pos之后的节点2.7 销毁链表 3. 单链表和顺序表对比 1. 什么是链表 链表是在逻辑结构…...

linux—基础命令及相关知识
1.0Linux的哲学思想(优势) 1、一切都是一个文件,一切硬件设备包括硬件接口都可以以文件形式显示 2、系统小型,轻量级,300个包(不装桌面的情况下) 3、避免令人困惑的用户界面(图形…...
Spring Boot 实现 WebSocket(注解方式)
本文介绍如何使用 Spring Boot 的注解方式实现一个简单的 WebSocket 服务,支持客户端与服务器之间进行实时通信。 1. 引入依赖 在 pom.xml 文件中添加 WebSocket 相关依赖。 <dependencies><!-- Spring Boot WebSocket 支持 --><dependency>&l…...

windows下Qt的安装方法
Qt Creator是个人非常喜欢的一款开发工具,喜欢用其来开发C和CPC平台项目,当然也可以用其来开发Android和Auto平台项目,但其现在采用离线安装,限于网络问题,安装速度非常慢。 现在介绍一种可以完成快速的安装方法。 下…...
嵌入式面试题 ARM常见面试题
一.ARM内核分为哪几类?他们之间有什么区别? ARM内核主要分为三类,Cortex-A,Cortex-R,Cortex-M三种,A代表Applications,向用户提供全方位解决方案,主要用于复制的应用场合,比如智能手机、移动计算平台,数字电视、机顶盒、打印机或服务器等。R代表Real-Time Embedded,…...

分布式调度器--Spring Task 的使用
目录 1、启动类(App.java)上加EnableScheduling注解: 开启基于注解的任务调度器 2、同步定时任务 3、多线程(异步)定时任务 3.1 配置线程池 3.2 开启异步支持 3.3 定义异步方法 4、Api说明 4.1 fixedDelay 4.…...

Java应用程序的测试覆盖率之设计与实现(四)-- jacoco-maven-plugin
一、什么是jacoco-maven-plugin jacoco源码jacoco文档 除了使用jacoco.cli.jar导出并生成覆盖率报告外,还可以使用jacoco-maven-plugin,它是maven集成了jacoco的一款插件。 在工程pom.xml里配置插件jacoco-maven-plugin。 <plugin><groupId&g…...

UI 提供的 progress-step 要怎么实现?
前言 这天突然收到了 UI 修改设计稿的消息通知:“xxx 已修改 xxx 项目并 了你,请及时查看变更内容”,一条、两条、三条 …,修改消息铺天盖地而来,然后就什么都看不到了(因为我选择开启消息免打扰…...

DBSwitch和Seatunel
一、DBSwitch 什么是DBSwitch?它主要用在什么场景? 通过步骤分析可以看到这个是通过配置数据源,采用一次性或定时方案,同步到数据仓库的指定表,并且指定映射关系的工具。有点类似于flinkcdc的增量同步。 参考: dbs…...
【日志】力扣刷题 -- 轮转数组
2024.10.06 【力扣刷题】 经典面试150—转轮数组—中等 189. 轮转数组 - 力扣(LeetCode) 第一次做,暴力循环 // 超出时间限制 void rotate(int* nums, int numsSize, int k) {for(int i 0; i < k; i){int right numsSize - 1;int temp…...
Java 项目 Dockerfile 示例:从基础镜像选择到环境变量配置的详细指南
Java 项目 Dockerfile 示例:从基础镜像选择到环境变量配置的详细指南 本文提供了一个 Java 项目的 Dockerfile 示例,展示了如何为 Java 应用创建高效的 Docker 镜像。Dockerfile 从 OpenJDK 8 的 Java 运行环境开始,配置了工作目录和 JVM 启…...

WebGL编程指南 - 高级变换与动画基础
学习使用一个矩阵变换库,该库封装了矩阵运算的数学细节。快速上手使用该矩阵库,对图形进行复合变换。在该矩阵库的帮助下,实现简单的动画效果。 矩阵变换库:cuon-matrix.js OpenGL中的函数: 书中 cuon-matrix.js 函数…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
Admin.Net中的消息通信SignalR解释
定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...
C++ 基础特性深度解析
目录 引言 一、命名空间(namespace) C 中的命名空间 与 C 语言的对比 二、缺省参数 C 中的缺省参数 与 C 语言的对比 三、引用(reference) C 中的引用 与 C 语言的对比 四、inline(内联函数…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

消息队列系统设计与实践全解析
文章目录 🚀 消息队列系统设计与实践全解析🔍 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡💡 权衡决策框架 1.3 运维复杂度评估🔧 运维成本降低策略 🏗️ 二、典型架构设计2.1 分布式事务最终一致…...
人工智能 - 在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型
在Dify、Coze、n8n、FastGPT和RAGFlow之间做出技术选型。这些平台各有侧重,适用场景差异显著。下面我将从核心功能定位、典型应用场景、真实体验痛点、选型决策关键点进行拆解,并提供具体场景下的推荐方案。 一、核心功能定位速览 平台核心定位技术栈亮…...
Java 与 MySQL 性能优化:MySQL 慢 SQL 诊断与分析方法详解
文章目录 一、开启慢查询日志,定位耗时SQL1.1 查看慢查询日志是否开启1.2 临时开启慢查询日志1.3 永久开启慢查询日志1.4 分析慢查询日志 二、使用EXPLAIN分析SQL执行计划2.1 EXPLAIN的基本使用2.2 EXPLAIN分析案例2.3 根据EXPLAIN结果优化SQL 三、使用SHOW PROFILE…...

数据分析六部曲?
引言 上一章我们说到了数据分析六部曲,何谓六部曲呢? 其实啊,数据分析没那么难,只要掌握了下面这六个步骤,也就是数据分析六部曲,就算你是个啥都不懂的小白,也能慢慢上手做数据分析啦。 第一…...