当前位置: 首页 > ds >正文

Unity-GC详解

什么是GC呢?

简单的说,Unity的GC就是一个专门针对动态内存(堆内存)进行自动回收的机制(Garbge Collector)

但是这里,我们就要说清楚一些Unity和C#的更低层次的东西了:

我们都知道Unity是用C#写成的,或者说我们的源码是C#构成的,按照正常的流程,我们要将代码进行编译后再汇编才能变成机器可以阅读的机器码。其中关于这个编译方法主要有两种:

可以看到两种编译方式的主要区别就在于CIL(中间语言)到机器码之间的这个过程,Mono方案是生成JIT/AOT而IL2CPP是生成C++,具体区别如图所示,简单的说就是Mono最大的好处就是支持热更新,其他不论性能还是安全性IL2CPP都更高一筹。

所以我们来讨论IL2CPP的情况下我们的GC:

所以我们真正的主角就是:Boehm GC

比较直白地说,我们的Bohem GC的运行原理就是遍历所有内存区域(如线程栈、全局变量、寄存器),将其中 ​符合地址范围和对齐规则​ 的数值视为 ​潜在指针,这些潜在指针指向的动态内存就是活跃对象,最后将所有的不活跃内存回收。

Bohem GC和C#/JAVA的GC以及Lua的GC的区别:

Bohem GC优化点:

一般来说,GC只负责回收堆上的内存,但是我们如果换个角度想:我们什么时候会去回收内存呢?往往是我们在堆上分配了一块新的内存,虽然二者并不是强关联关系,但是确实客观上存在可能。

因此,我们现在去考虑考虑哪些场景会导致我们的GC:

首先,C#中涉及到堆,我们很容易想到:

装箱:

装箱时,我们需要将原本存储在栈上的值类型复制到堆上开辟的新内存上,变成引用类型。这个过程中涉及到堆内存的分配,比如我们要是频繁进行装箱的话就会引发GC。

针对这种情况,我们最好的优化思路就是去减少装箱:这是我们的一个核心理念。

比如我们的泛型:

匿名方法:

我们都知道匿名方法在通过闭包捕获外部变量时,会生成一个匿名类,既然涉及到类(引用类型)那自然就会涉及到堆内存的分配,那么自然就会涉及到GC了。

int n = 1;
void Test()     
{Call(()=> n = 2);     
}

那么要如何去优化呢?

一般来说,我们可以把匿名方法要捕获的对象写成静态的,这样就不用生成匿名类来存储这个捕获的变量了(静态变量等同于类,直接通过类名访问);

static int n = 1; // 静态变量
void Func() {Call(() => n = 2); // 匿名方法直接访问静态变量
}

我们还可以利用委托来缓存匿名方法,这样我们只用在第一次调用委托时生成匿名类,后续我们就一直调用委托缓存中的匿名方法,不会生成新的匿名类。

int a = 1;          // 实例变量
Action action;      // 缓存委托实例
void Func() {if (action == null) { // 首次初始化委托action = () => a = 2; // 生成闭包(仅一次)}Call(action);    // 复用缓存的委托实例
}

字符串:

我们都知道C#中的string本身是不可变的,任何对string类型变量的操作都需要先复制一个源字符串再进行操作,那么这个时候旧的字符串就变成了无人使用的内存垃圾。

虽然当我们提到关于修改string类型对象的思路一般都是使用stringbuilder,但是实际上stringbuilder并没有那么好用,我们可以去使用一些其他的优化方法。

类和结构体:

这个就是基本都能想到的:结构体是值类型而类是引用类型,对于并不庞大的数据,能使用结构体的话优先使用结构体,不会涉及到堆上内存的分配就不会引发GC。

容器:

大多数我们使用的容器都支持动态扩容,那么每次动态扩容都会涉及到堆上的内存分配,所以尽可能地我们去减少容器的扩容。

Unity的GC和C#的GC对比:

http://www.xdnf.cn/news/1132.html

相关文章:

  • 面试网络基础知识 — IP地址
  • PyTorch 分布式 DistributedDataParallel (DDP)
  • Nordic外设GPIO[nrfx_gpiote_in_init函数报NRFX_ERROR_NO_MEM并且fatal error]
  • 门控循环单元(GRU)
  • LX10-MDK的使用技巧
  • 【Spring Boot基础】MyBatis的基础操作:增删查改、列名和属性名匹配 -- XML实现
  • 【Java面试笔记:基础】7.int和Integer有什么区别?
  • kubernetes》》k8s》》删除命名空间
  • Spring中配置 Bean 的两种方式:XML 配置 和 Java 配置类
  • 18.2基于Linux的INPUT子系统实验(详细编写程序)_csdn
  • IDEA 创建Maven 工程(图文)
  • dmncdm达梦新云缓存数据库主从集群安装部署详细步骤说明
  • Redis 系列之 Key 过期策略介绍
  • 09.传输层协议 ——— TCP协议
  • kotlin的kmp编程中遇到Unresolved reference ‘java‘问题
  • 鸿蒙应用开发:如何修改APP名称与APP的图标
  • 物联网蓬勃发展是助力楼宇自控技术迈向成熟的关键
  • 中电金信联合阿里云推出智能陪练Agent
  • 智能指针之设计模式4
  • BPC电波授时技术
  • 什么是爬虫?——从技术原理到现实应用的全面解析 III
  • HTTP 请求头与请求体:数据存储的底层逻辑与实践指南
  • leetcode day36 01背包问题 494
  • react 父子组件通信 子 直接到父, 父 forwardref子
  • 基于扣子(Coze.cn)与火山引擎构建高性能智能体的实践指南
  • 【Linux网络与网络编程】07.应用层协议HTTPS
  • LLM 论文精读(二)Training Compute-Optimal Large Language Models
  • Docker 数据卷
  • UML概览
  • Spark与Hadoop之间的联系和对比