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 函数…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...