Unity值类型和引用类型

我们都知道C#编程语言中,数据类型被分为了两种:

  1. 值类型
  2. 引用类型

那么什么是值类型?什么是引用类型呢?它们的区别又是什么?

为了搞清楚这些问题,我们先列举一下我们开发中会碰到的值类型和引用类型。

  • 常见的值类型为:byte,short,int,long,float,double,decimal,char,bool 和 struct
  • 常见的引用类型为:class array interface delegate string System.Object dynamic

为了更清晰的对比值类型和引用类型,我们从内存的分配和回收两个角度来进行分析

内存分配

我们都知道,创建对象就需要有一块内存来承载相应的对象,我们也知道,在程序运行过程中内存会分为栈内存和堆内存,那么到底我们的值类型和引用类型的内存是分配在哪块内存上了呢?
要搞清楚这个问题首先我们先要了解值类型和堆内存,内存分配的差异:

  • 值类型只需要一段单独的内存,用于存储实际的数据

  • 引用类型需要存储两段内存

    • 第一段存储实际的数据。
    • 第二段存储的是一个引用,指向实际数据的存放位置。

    其实很多熟悉开发的小伙伴都口熟能详的知道一个概念,“值类型被存储在内存栈上,引用类型被存储在内存堆上”。这句话对不对呢。继续往下看…
    其实这句话呢,也对也不对,但要分使用场景

    数据不是其它类型的成员的情况下“值类型被存储在内存栈上,引用类型被存储在内存堆上”,大致如下图所示:
    在这里插入图片描述

但我们实际开发中很多时候类型都不是单独存在的,看下面的一段代码:

  public class ClassA{
    public int a;
    public string b;
  }

看到代码是不是感觉 a内存分配在内存栈,b内存分配在内存堆。很遗憾,实际情况是a和b都被分配在内存堆中。

那么哪个环节出现问题了呢?
因为a是ClassA的成员属性,而ClassA是一个引用类型,所以ClassA的数据部分是被存储在内存堆上的,大致如下图所示:
在这里插入图片描述

总结:

引用类型的数据一定是被分配在内存堆上的,而引用类型的引用以及值类型的数据却并不一定分配在内存栈上。

  1. 局部变量:

引用类型的引用和值类型的数据分配在内存栈上

  1. 公共变量

引用类型的引用和值类型的数据的分配根承载它的对象所在的内存有关,如果承载它的对象在堆内存中那么它就跟着被分在堆内存中,如果承载它的对象被分配在栈内存中那么它就跟着被分在栈内存中。

内存回收

在说回收之前我们需要先了解一下栈内存和堆内存的定义和结构如下:

栈内存

栈是一个内存数组,是一个LIFO(last-in first-out,后进先出)的数据结构。栈存储几种类型的数据:某些类型变量的值、程序当前的执行环境、传递给方法的参数。

栈的特点:(1)数据只能从栈的顶端插入和删除。(2)把数据放到栈顶称为入栈。(3)从栈顶删除数据称为出栈。(4)内存连续 (5)内存自行维护

堆内存

堆是一块内存区域,在堆里可以分配大块的内存用于存储某种类型的数据对象。与栈不同,堆里的内存能够以任意顺序存入和移除。
堆的特点: (1)内存无序。 (2)内存不可自行维护需要借助CLR的GC机制

由于栈内存的内存连续性以及内存的自行维护,所以栈内存的申请和释放相对于堆内存要快。
而堆内存的内存回收完全借助于CLR的GC机制,什么时候回收几乎是不可控的,且由于堆内存的不连续性的特点,在GC之后容易产生内存碎片,从而造成内存浪费。

什么时候触发GC?

  1. 在堆内存上进行内存分配操作时,内存不够的时候会触发GC
  2. 自动触发,Unity会不定时的自动触发GC
  3. 代码强制执行

GC是怎样工作的?

  1. 挂起所有正在运行的线程
  2. 检查堆内存上的每个对象
  3. 搜索对象的所有引用
  4. 没有被引用的对象都是垃圾,被标记为可删除
  5. 遍历删除所有被标记的对象,释放内存

看到GC的工作机制你就会知道一次GC是多么的困难,并且随着我们的程序复杂性的提高,占用的CPU算力也会越高就会造成程序卡顿,所以在项目开发过程中我们一定要想办法减少GC,或选择在合适的位置进行GC

怎么减少GC?

  1. 对象池
  2. stringbuilder的使用
  3. 减少装箱操作
  4. 避免频繁的调用协程,每一次StartCoroutine()实际上是new一个新的对象
  5. 用for代替foreach foreach会在堆上产生一个system.object

最后我们简单用一个示例图来模拟一下一个引用类型的申请:

在这里插入图片描述

  • 13
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Unity中,枚举类型(enum)用于定义一组相关的符号常量,以便在程序运行从编译已经设定的固定数目的选择中做出决定。枚举类型的声明使用enum关键字。在Unity中,枚举类型通常用于定义一组特定的选项,例如游戏中的角色类型、道具类型等。 在给定的引用\[1\]中,展示了在Unity中使用枚举类型的示例代码。在这个示例中,定义了一个名为Fruit的枚举类型,包含了三个选项:Apple、Pear和Banana。通过使用Enum.GetNames和Enum.GetValues方法,可以分别获取枚举类型的名称和,并进行遍历和输出。 在Unity中,使用枚举类型可以方便地管理和使用一组固定的选项,提高代码的可读性和可维护性。通过枚举类型,可以避免使用魔法数字或字符串,使代码更加清晰和易于理解。 总结起来,Unity中的枚举类型(enum)用于定义一组相关的符号常量,以便在程序运行从编译已经设定的固定数目的选择中做出决定。它可以提高代码的可读性和可维护性,使代码更加清晰和易于理解。 #### 引用[.reference_title] - *1* [Unity 基础 之 实现枚举(enum/Enum)遍历的三种简单方法(foreach/for)](https://blog.csdn.net/u014361280/article/details/115945198)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Unity 基础 之 Enum(enum) 枚举 的简单介绍,和枚举变量同赋值多个,并且分解枚举变量包含多个](https://blog.csdn.net/u014361280/article/details/114587433)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

司军礼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值